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

Compare commits

...

21 Commits
3.0 ... 3.1

Author SHA1 Message Date
Paweł Jastrzębski
9d267a6cc4 Updated README and version bump 2013-07-22 08:43:35 +02:00
Paweł Jastrzębski
462f24149b Implemented Devernay idea 2013-07-22 08:32:59 +02:00
Paweł Jastrzębski
4744b62f91 Interruption fix 2013-07-21 20:25:14 +02:00
Paweł Jastrzębski
08244e7fdc Conversion can be now interrupted 2013-07-21 20:18:04 +02:00
Paweł Jastrzębski
f64fb1bee1 Multiselect - OSX fix 2013-07-21 19:13:39 +02:00
Paweł Jastrzębski
743c3b2466 Added multiselect to add file/directory dialogs 2013-07-21 18:24:24 +02:00
Paweł Jastrzębski
aefa36fef8 Refactored KindleGen error handling 2013-07-11 13:25:32 +02:00
Paweł Jastrzębski
d7f6503196 Added profile: Kindle for Android 2013-07-11 11:47:18 +02:00
Paweł Jastrzębski
3375b8c898 Don't stop conversion if KindleGen return only warnings 2013-07-11 11:01:35 +02:00
Paweł Jastrzębski
52e5919ccd Bucket of dirty hax to improve readability on Linux/OSX 2013-07-10 09:05:44 +02:00
Paweł Jastrzębski
1c2e57adb6 Updated status messages 2013-07-10 08:50:52 +02:00
Paweł Jastrzębski
2e99d6ee0a Updated status messages 2013-07-10 08:29:14 +02:00
Paweł Jastrzębski
6744815f77 Fixed JobList scroll bars 2013-07-10 08:24:13 +02:00
Paweł Jastrzębski
0ba44ab2d3 HTML tag support for addMessage() 2013-07-10 07:51:19 +02:00
Paweł Jastrzębski
a6006450de Improved upscale/stretch options handling 2013-07-08 11:07:37 +02:00
Paweł Jastrzębski
c20e2ba451 Fixed row alignment (#55) 2013-07-04 15:32:15 +02:00
Paweł Jastrzębski
7a0b387c1c Small tweak of NoSplit option 2013-07-04 15:05:16 +02:00
Ciro Mattia Gonano
fdfe5fbe39 Disable horizontal mode check when "no split/rotate" is checked. 2013-07-04 11:50:20 +02:00
Paweł Jastrzębski
35751efad5 Little tweaks 2013-06-28 00:08:36 +02:00
Mateusz
7005c9e40a Fix misleading message when processing empty directories 2013-06-27 23:40:30 +02:00
Paweł Jastrzębski
118cf25ff7 Older UnRAR exit code is 7 when it is called without parameters 2013-06-27 18:13:39 +02:00
9 changed files with 275 additions and 109 deletions

3
KCC.ui
View File

@@ -59,6 +59,9 @@
</font> </font>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>9</number>
</property>
<item row="1" column="0"> <item row="1" column="0">
<widget class="QCheckBox" name="ProcessingBox"> <widget class="QCheckBox" name="ProcessingBox">
<property name="focusPolicy"> <property name="focusPolicy">

View File

@@ -24,9 +24,6 @@ You can find the latest released binary at the following links:
- **OS X:** [http://kcc.vulturis.eu/OSX/](http://kcc.vulturis.eu/OSX/) - **OS X:** [http://kcc.vulturis.eu/OSX/](http://kcc.vulturis.eu/OSX/)
- **Linux:** Just download sourcecode and launch: `python kcc.py` - **Linux:** Just download sourcecode and launch: `python kcc.py`
_It has been reported by a couple of users that version 2.10 crashing on OSX at start. We don't know if that issue still exist in version 3.0.
If it happens to you please append your message to [Issue #52](https://github.com/ciromattia/kcc/issues/52)._
## INPUT FORMATS ## INPUT FORMATS
**KCC** can understand and convert, at the moment, the following file types: **KCC** can understand and convert, at the moment, the following file types:
- PNG, JPG, GIF, TIFF, BMP - PNG, JPG, GIF, TIFF, BMP
@@ -70,7 +67,7 @@ Options:
--version show program's version number and exit --version show program's version number and exit
-h, --help show this help message and exit -h, --help show this help message and exit
-p PROFILE, --profile=PROFILE -p PROFILE, --profile=PROFILE
Device profile (Choose one among K1, K2, K3, K4NT, K4T, KDX, KDXG, KHD, KF, KFHD, KFHD8) [Default=KHD] Device profile (Choose one among K1, K2, K3, K4NT, K4T, KDX, KDXG, KHD, KF, KFHD, KFHD8, KFA) [Default=KHD]
-t TITLE, --title=TITLE -t TITLE, --title=TITLE
Comic title [Default=filename] Comic title [Default=filename]
-m, --manga-style Manga style (Right-to-left reading and splitting) [Default=False] -m, --manga-style Manga style (Right-to-left reading and splitting) [Default=False]
@@ -213,8 +210,12 @@ The app relies and includes the following scripts/binaries:
* Added support for custom width/height * Added support for custom width/height
* Added option to disable color conversion * Added option to disable color conversion
####3.1:
* Added profile: Kindle for Android
* Add file/directory dialogs now support multiselect
* Many small fixes and tweaks
## KNOWN ISSUES ## KNOWN ISSUES
* _Add directory_ dialog allow to select multiple directories but they are not added to job list. [QT bug.](https://bugreports.qt-project.org/browse/QTBUG-21372)
* Removing SRCS headers sometimes fail in 32bit enviroments. Due to memory limitations. * Removing SRCS headers sometimes fail in 32bit enviroments. Due to memory limitations.
## COPYRIGHT ## COPYRIGHT

2
kcc.py
View File

@@ -17,7 +17,7 @@
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE. # PERFORMANCE OF THIS SOFTWARE.
# #
__version__ = '3.0' __version__ = '3.1'
__license__ = 'ISC' __license__ = 'ISC'
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>' __copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'

View File

@@ -17,7 +17,7 @@
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE. # PERFORMANCE OF THIS SOFTWARE.
__version__ = '3.0' __version__ = '3.1'
__license__ = 'ISC' __license__ = 'ISC'
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>' __copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
@@ -27,12 +27,14 @@ import sys
import shutil import shutil
import traceback import traceback
import urllib2 import urllib2
import time
import comic2ebook import comic2ebook
import kindlestrip import kindlestrip
from image import ProfileData from image import ProfileData
from subprocess import call, Popen, STDOUT, PIPE from subprocess import call, Popen, STDOUT, PIPE
from PyQt4 import QtGui, QtCore from PyQt4 import QtGui, QtCore
from xml.dom.minidom import parse from xml.dom.minidom import parse
from HTMLParser import HTMLParser
class Icons: class Icons:
@@ -57,6 +59,19 @@ class Icons:
self.error.addPixmap(QtGui.QPixmap(":/Status/icons/error.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.error.addPixmap(QtGui.QPixmap(":/Status/icons/error.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
class HTMLStripper(HTMLParser):
def __init__(self):
HTMLParser.__init__(self)
self.reset()
self.fed = []
def handle_data(self, d):
self.fed.append(d)
def get_data(self):
return ''.join(self.fed)
# noinspection PyBroadException # noinspection PyBroadException
class VersionThread(QtCore.QThread): class VersionThread(QtCore.QThread):
def __init__(self, parent): def __init__(self, parent):
@@ -74,7 +89,8 @@ class VersionThread(QtCore.QThread):
return return
latestVersion = XML.childNodes[0].getElementsByTagName('latest')[0].childNodes[0].toxml() latestVersion = XML.childNodes[0].getElementsByTagName('latest')[0].childNodes[0].toxml()
if tuple(map(int, (latestVersion.split(".")))) > tuple(map(int, (__version__.split(".")))): if tuple(map(int, (latestVersion.split(".")))) > tuple(map(int, (__version__.split(".")))):
self.emit(QtCore.SIGNAL("addMessage"), 'New version is available!', 'warning') self.emit(QtCore.SIGNAL("addMessage"), '<a href="http://kcc.vulturis.eu/">'
'<b>New version is available!</b></a>', 'warning')
# noinspection PyBroadException # noinspection PyBroadException
@@ -86,6 +102,15 @@ class WorkerThread(QtCore.QThread):
def __del__(self): def __del__(self):
self.wait() self.wait()
def sync(self):
self.conversionAlive = self.parent.conversionAlive
def clean(self):
self.parent.needClean = True
self.emit(QtCore.SIGNAL("hideProgressBar"))
self.emit(QtCore.SIGNAL("addMessage"), '<b>Conversion interrupted.</b>', 'error')
self.emit(QtCore.SIGNAL("modeConvert"), True)
def run(self): def run(self):
self.emit(QtCore.SIGNAL("modeConvert"), False) self.emit(QtCore.SIGNAL("modeConvert"), False)
profile = ProfileData.ProfileLabels[str(GUI.DeviceBox.currentText())] profile = ProfileData.ProfileLabels[str(GUI.DeviceBox.currentText())]
@@ -102,7 +127,7 @@ class WorkerThread(QtCore.QThread):
if self.parent.currentMode > 1: if self.parent.currentMode > 1:
if GUI.ProcessingBox.isChecked(): if GUI.ProcessingBox.isChecked():
argv.append("--noprocessing") argv.append("--noprocessing")
if GUI.UpscaleBox.isChecked() and not GUI.StretchBox.isChecked(): if GUI.UpscaleBox.isChecked():
argv.append("--upscale") argv.append("--upscale")
if GUI.NoRotateBox.isChecked(): if GUI.NoRotateBox.isChecked():
argv.append("--nosplitrotate") argv.append("--nosplitrotate")
@@ -125,8 +150,12 @@ class WorkerThread(QtCore.QThread):
currentJobs.append(str(GUI.JobList.item(i).text())) currentJobs.append(str(GUI.JobList.item(i).text()))
GUI.JobList.clear() GUI.JobList.clear()
for job in currentJobs: for job in currentJobs:
time.sleep(0.5)
if not self.conversionAlive:
self.clean()
return
self.errors = False self.errors = False
self.emit(QtCore.SIGNAL("addMessage"), 'Source: ' + job, 'info') self.emit(QtCore.SIGNAL("addMessage"), '<b>Source:</b> ' + job, 'info')
if str(GUI.FormatBox.currentText()) == 'CBZ': if str(GUI.FormatBox.currentText()) == 'CBZ':
self.emit(QtCore.SIGNAL("addMessage"), 'Creating CBZ file...', 'info') self.emit(QtCore.SIGNAL("addMessage"), 'Creating CBZ file...', 'info')
else: else:
@@ -136,26 +165,57 @@ class WorkerThread(QtCore.QThread):
try: try:
outputPath = comic2ebook.main(jobargv, self) outputPath = comic2ebook.main(jobargv, self)
self.emit(QtCore.SIGNAL("hideProgressBar")) self.emit(QtCore.SIGNAL("hideProgressBar"))
except UserWarning as warn:
if not self.conversionAlive:
self.clean()
return
else:
self.errors = True
self.emit(QtCore.SIGNAL("addMessage"), str(warn), 'warning')
self.emit(QtCore.SIGNAL("addMessage"), 'KCC failed to create output file!', 'warning')
except Exception as err: except Exception as err:
self.errors = True self.errors = True
type_, value_, traceback_ = sys.exc_info() type_, value_, traceback_ = sys.exc_info()
self.emit(QtCore.SIGNAL("showDialog"), "Error during conversion %s:\n\n%s\n\nTraceback:\n%s" self.emit(QtCore.SIGNAL("showDialog"), "Error during conversion %s:\n\n%s\n\nTraceback:\n%s"
% (jobargv[-1], str(err), traceback.format_tb(traceback_))) % (jobargv[-1], str(err), traceback.format_tb(traceback_)))
self.emit(QtCore.SIGNAL("addMessage"), 'KCC failed to create EPUB!', 'error') self.emit(QtCore.SIGNAL("addMessage"), 'KCC failed to create EPUB!', 'error')
if not self.conversionAlive:
os.remove(outputPath)
self.clean()
return
if not self.errors: if not self.errors:
if str(GUI.FormatBox.currentText()) == 'CBZ': if str(GUI.FormatBox.currentText()) == 'CBZ':
self.emit(QtCore.SIGNAL("addMessage"), 'Creating CBZ file... Done!', 'info', True) self.emit(QtCore.SIGNAL("addMessage"), 'Creating CBZ file... Done!', 'info', True)
else: else:
self.emit(QtCore.SIGNAL("addMessage"), 'Creating EPUB file... Done!', 'info', True) self.emit(QtCore.SIGNAL("addMessage"), 'Creating EPUB file... Done!', 'info', True)
if str(GUI.FormatBox.currentText()) == 'MOBI': if str(GUI.FormatBox.currentText()) == 'MOBI':
if not os.path.getsize(outputPath) > 314572800:
self.emit(QtCore.SIGNAL("addMessage"), 'Creating MOBI file...', 'info') self.emit(QtCore.SIGNAL("addMessage"), 'Creating MOBI file...', 'info')
self.emit(QtCore.SIGNAL("progressBarTick"), 1) self.emit(QtCore.SIGNAL("progressBarTick"), 1)
try: try:
retcode = call('kindlegen -verbose "' + outputPath + '"', shell=True) self.kindlegenErrorCode = 0
if os.path.getsize(outputPath) < 367001600:
output = Popen('kindlegen "' + outputPath + '"', 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
else:
# ERROR: EPUB too big
self.kindlegenErrorCode = 23026
except: except:
# ERROR: Unknown generic error
self.kindlegenErrorCode = 1
continue continue
if retcode == 0: if not self.conversionAlive:
os.remove(outputPath)
os.remove(outputPath.replace('.epub', '.mobi'))
self.clean()
return
if self.kindlegenErrorCode == 0:
self.emit(QtCore.SIGNAL("addMessage"), 'Creating MOBI file... Done!', 'info', True) self.emit(QtCore.SIGNAL("addMessage"), 'Creating MOBI file... Done!', 'info', True)
self.emit(QtCore.SIGNAL("addMessage"), 'Removing SRCS header...', 'info') self.emit(QtCore.SIGNAL("addMessage"), 'Removing SRCS header...', 'info')
os.remove(outputPath) os.remove(outputPath)
@@ -175,32 +235,47 @@ class WorkerThread(QtCore.QThread):
self.emit(QtCore.SIGNAL("addMessage"), self.emit(QtCore.SIGNAL("addMessage"),
'MOBI file will work correctly but it will be highly oversized.', 'warning') 'MOBI file will work correctly but it will be highly oversized.', 'warning')
else: else:
epubSize = (os.path.getsize(outputPath))/1024/1024
os.remove(outputPath) os.remove(outputPath)
if os.path.exists(outputPath.replace('.epub', '.mobi')): if os.path.exists(outputPath.replace('.epub', '.mobi')):
os.remove(outputPath.replace('.epub', '.mobi')) os.remove(outputPath.replace('.epub', '.mobi'))
self.emit(QtCore.SIGNAL("addMessage"), 'KindleGen failed to create MOBI!', 'error') self.emit(QtCore.SIGNAL("addMessage"), 'KindleGen failed to create MOBI!', 'error')
self.emit(QtCore.SIGNAL("addMessage"), 'Try converting a smaller batch.', 'error') if self.kindlegenErrorCode == 1 and self.kindlegenError:
else: self.emit(QtCore.SIGNAL("showDialog"), "KindleGen error:\n\n" + self.kindlegenError)
excess = (os.path.getsize(outputPath) - 314572800)/1024/1024 if self.kindlegenErrorCode == 23026:
os.remove(outputPath) self.emit(QtCore.SIGNAL("addMessage"), 'Created EPUB file was too big.',
self.emit(QtCore.SIGNAL("addMessage"), 'Created EPUB file is too big for KindleGen!', 'error') 'error')
self.emit(QtCore.SIGNAL("addMessage"), 'Limit exceeded by ' + str(excess) + self.emit(QtCore.SIGNAL("addMessage"), 'EPUB file: ' + str(epubSize) + 'MB.'
' MB. Try converting a smaller batch.', 'error') ' Supported size: ~300MB.', 'error')
self.emit(QtCore.SIGNAL("hideProgressBar")) self.emit(QtCore.SIGNAL("hideProgressBar"))
self.parent.needClean = True self.parent.needClean = True
self.emit(QtCore.SIGNAL("addMessage"), 'All jobs completed.', 'info') self.emit(QtCore.SIGNAL("addMessage"), '<b>All jobs completed.</b>', 'info')
self.emit(QtCore.SIGNAL("modeConvert"), True) self.emit(QtCore.SIGNAL("modeConvert"), True)
# noinspection PyBroadException # noinspection PyBroadException
class Ui_KCC(object): class Ui_KCC(object):
def selectDir(self): def selectDir(self):
# Dialog allow to select multiple directories but we can't parse that. QT Bug.
if self.needClean: if self.needClean:
self.needClean = False self.needClean = False
GUI.JobList.clear() GUI.JobList.clear()
dname = QtGui.QFileDialog.getExistingDirectory(MainWindow, 'Select directory', self.lastPath) # Dirty, dirty way but OS native QFileDialogs don't support directory multiselect
dirDialog = QtGui.QFileDialog(MainWindow, 'Select directory', self.lastPath)
dirDialog.setFileMode(dirDialog.Directory)
dirDialog.setOption(dirDialog.ShowDirsOnly, True)
dirDialog.setOption(dirDialog.DontUseNativeDialog, True)
l = dirDialog.findChild(QtGui.QListView, "listView")
t = dirDialog.findChild(QtGui.QTreeView)
if l:
l.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
if t:
t.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
if dirDialog.exec_() == 1:
dnames = dirDialog.selectedFiles()
else:
dnames = ""
# Lame UTF-8 security measure # Lame UTF-8 security measure
for dname in dnames:
try: try:
str(dname) str(dname)
except Exception: except Exception:
@@ -208,6 +283,8 @@ class Ui_KCC(object):
QtGui.QMessageBox.Ok) QtGui.QMessageBox.Ok)
return return
if str(dname) != "": if str(dname) != "":
if sys.platform == 'win32':
dname = dname.replace('/', '\\')
self.lastPath = os.path.abspath(os.path.join(str(dname), os.pardir)) self.lastPath = os.path.abspath(os.path.join(str(dname), os.pardir))
GUI.JobList.addItem(dname) GUI.JobList.addItem(dname)
@@ -216,12 +293,13 @@ class Ui_KCC(object):
self.needClean = False self.needClean = False
GUI.JobList.clear() GUI.JobList.clear()
if self.UnRAR: if self.UnRAR:
fname = QtGui.QFileDialog.getOpenFileName(MainWindow, 'Select file', self.lastPath, fnames = QtGui.QFileDialog.getOpenFileNames(MainWindow, 'Select file', self.lastPath,
'*.cbz *.cbr *.zip *.rar *.pdf') '*.cbz *.cbr *.zip *.rar *.pdf')
else: else:
fname = QtGui.QFileDialog.getOpenFileName(MainWindow, 'Select file', self.lastPath, fnames = QtGui.QFileDialog.getOpenFileNames(MainWindow, 'Select file', self.lastPath,
'*.cbz *.zip *.pdf') '*.cbz *.zip *.pdf')
# Lame UTF-8 security measure # Lame UTF-8 security measure
for fname in fnames:
try: try:
str(fname) str(fname)
except Exception: except Exception:
@@ -268,13 +346,19 @@ class Ui_KCC(object):
GUI.OptionsExpert.setEnabled(False) GUI.OptionsExpert.setEnabled(False)
GUI.MangaBox.setEnabled(True) GUI.MangaBox.setEnabled(True)
def modeExpert(self): def modeExpert(self, KFA=False):
self.modeAdvanced() self.modeAdvanced()
self.currentMode = 3 self.currentMode = 3
MainWindow.setMinimumSize(QtCore.QSize(420, 380)) MainWindow.setMinimumSize(QtCore.QSize(420, 380))
MainWindow.setMaximumSize(QtCore.QSize(420, 380)) MainWindow.setMaximumSize(QtCore.QSize(420, 380))
MainWindow.resize(420, 380) MainWindow.resize(420, 380)
GUI.OptionsExpert.setEnabled(True) GUI.OptionsExpert.setEnabled(True)
if KFA:
GUI.ColorBox.setCheckState(2)
GUI.FormatBox.setCurrentIndex(0)
GUI.FormatBox.setEnabled(False)
else:
GUI.FormatBox.setEnabled(True)
GUI.MangaBox.setCheckState(0) GUI.MangaBox.setCheckState(0)
GUI.MangaBox.setEnabled(False) GUI.MangaBox.setEnabled(False)
@@ -286,19 +370,33 @@ class Ui_KCC(object):
GUI.ClearButton.setEnabled(enable) GUI.ClearButton.setEnabled(enable)
GUI.FileButton.setEnabled(enable) GUI.FileButton.setEnabled(enable)
GUI.DeviceBox.setEnabled(enable) GUI.DeviceBox.setEnabled(enable)
GUI.ConvertButton.setEnabled(enable)
GUI.FormatBox.setEnabled(enable) GUI.FormatBox.setEnabled(enable)
GUI.OptionsBasic.setEnabled(enable) GUI.OptionsBasic.setEnabled(enable)
GUI.OptionsAdvanced.setEnabled(enable) GUI.OptionsAdvanced.setEnabled(enable)
GUI.OptionsAdvancedGamma.setEnabled(enable) GUI.OptionsAdvancedGamma.setEnabled(enable)
GUI.OptionsExpert.setEnabled(enable) GUI.OptionsExpert.setEnabled(enable)
if enable: if enable:
self.conversionAlive = False
self.worker.sync()
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(":/Other/icons/convert.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
GUI.ConvertButton.setIcon(icon)
GUI.ConvertButton.setText('Convert')
GUI.ConvertButton.setEnabled(True)
if self.currentMode == 1: if self.currentMode == 1:
self.modeBasic() self.modeBasic()
elif self.currentMode == 2: elif self.currentMode == 2:
self.modeAdvanced() self.modeAdvanced()
elif self.currentMode == 3: elif self.currentMode == 3:
self.modeExpert() self.modeExpert()
else:
self.conversionAlive = True
self.worker.sync()
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(":/Other/icons/clear.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
GUI.ConvertButton.setIcon(icon)
GUI.ConvertButton.setText('Abort')
GUI.ConvertButton.setEnabled(True)
def changeGamma(self, value): def changeGamma(self, value):
value = float(value) value = float(value)
@@ -309,30 +407,64 @@ class Ui_KCC(object):
GUI.GammaLabel.setText('Gamma: ' + str(value)) GUI.GammaLabel.setText('Gamma: ' + str(value))
self.GammaValue = value self.GammaValue = value
def changeDevice(self, value, start=False): def toggleNoSplitRotate(self, value):
if value == 11 and (start or self.currentMode != 3): if value:
GUI.RotateBox.setEnabled(False)
GUI.RotateBox.setChecked(False)
else:
GUI.RotateBox.setEnabled(True)
def toggleUpscale(self, value):
if value:
GUI.StretchBox.setChecked(False)
def toggleStretch(self, value):
if value:
GUI.UpscaleBox.setChecked(False)
def changeDevice(self, value):
if value == 12:
GUI.BasicModeButton.setEnabled(False) GUI.BasicModeButton.setEnabled(False)
GUI.AdvModeButton.setEnabled(False) GUI.AdvModeButton.setEnabled(False)
self.addMessage('<a href="https://github.com/ciromattia/kcc/wiki/NonKindle-devices">'
'List of supported Non-Kindle devices</a>', 'info')
self.modeExpert() self.modeExpert()
elif value == 11:
GUI.BasicModeButton.setEnabled(False)
GUI.AdvModeButton.setEnabled(False)
self.modeExpert(True)
elif self.currentMode == 3: elif self.currentMode == 3:
GUI.BasicModeButton.setEnabled(True) GUI.BasicModeButton.setEnabled(True)
GUI.AdvModeButton.setEnabled(True) GUI.AdvModeButton.setEnabled(True)
self.modeBasic() self.modeBasic()
if value in [0, 1, 5, 6, 7, 8, 9, 11]: if value in [0, 1, 5, 6, 7, 8, 9, 12]:
GUI.QualityBox.setCheckState(0) GUI.QualityBox.setCheckState(0)
GUI.QualityBox.setEnabled(False) GUI.QualityBox.setEnabled(False)
else: else:
GUI.QualityBox.setEnabled(True) GUI.QualityBox.setEnabled(True)
def stripTags(self, html):
s = HTMLStripper()
s.feed(html)
return s.get_data()
def addMessage(self, message, icon=None, replace=False): def addMessage(self, message, icon=None, replace=False):
if icon: if icon:
icon = eval('self.icons.' + icon) icon = eval('self.icons.' + icon)
item = QtGui.QListWidgetItem(icon, message) item = QtGui.QListWidgetItem(icon, ' ' + self.stripTags(message))
else: else:
item = QtGui.QListWidgetItem(message) item = QtGui.QListWidgetItem(' ' + self.stripTags(message))
if replace: if replace:
GUI.JobList.takeItem(GUI.JobList.count()-1) GUI.JobList.takeItem(GUI.JobList.count()-1)
label = QtGui.QLabel(message)
label.setOpenExternalLinks(True)
if sys.platform == 'darwin':
font = QtGui.QFont()
font.setPointSize(11)
label.setFont(font)
item.setTextColor(QtGui.QColor("white"))
GUI.JobList.addItem(item) GUI.JobList.addItem(item)
GUI.JobList.setItemWidget(item, label)
GUI.JobList.scrollToBottom() GUI.JobList.scrollToBottom()
def showDialog(self, message): def showDialog(self, message):
@@ -350,6 +482,12 @@ class Ui_KCC(object):
GUI.ProgressBar.setValue(GUI.ProgressBar.value() + 1) GUI.ProgressBar.setValue(GUI.ProgressBar.value() + 1)
def convertStart(self): def convertStart(self):
if self.conversionAlive:
GUI.ConvertButton.setEnabled(False)
self.addMessage('Process will be interrupted. Please wait.', 'warning')
self.conversionAlive = False
self.worker.sync()
else:
if self.needClean: if self.needClean:
self.needClean = False self.needClean = False
GUI.JobList.clear() GUI.JobList.clear()
@@ -403,10 +541,11 @@ class Ui_KCC(object):
self.options = self.options.toPyObject() self.options = self.options.toPyObject()
self.worker = WorkerThread(self) self.worker = WorkerThread(self)
self.versionCheck = VersionThread(self) self.versionCheck = VersionThread(self)
self.conversionAlive = False
self.needClean = True self.needClean = True
self.addMessage('Welcome!', 'info') self.addMessage('<b>Welcome!</b>', 'info')
self.addMessage('Remember: all options have additional informations in tooltips.', 'info') self.addMessage('<b>Remember:</b> All options have additional informations in tooltips.', 'info')
if call('kindlegen', stdout=PIPE, stderr=STDOUT, shell=True) == 0: if call('kindlegen', stdout=PIPE, stderr=STDOUT, shell=True) == 0:
self.KindleGen = True self.KindleGen = True
formats = ['MOBI', 'EPUB', 'CBZ'] formats = ['MOBI', 'EPUB', 'CBZ']
@@ -415,18 +554,23 @@ class Ui_KCC(object):
if "Amazon kindlegen" in line: if "Amazon kindlegen" in line:
versionCheck = line.split('V')[1].split(' ')[0] versionCheck = line.split('V')[1].split(' ')[0]
if tuple(map(int, (versionCheck.split(".")))) < tuple(map(int, ('2.9'.split(".")))): if tuple(map(int, (versionCheck.split(".")))) < tuple(map(int, ('2.9'.split(".")))):
self.addMessage('Your kindlegen is outdated! Creating MOBI might fail.' self.addMessage('Your <a href="http://www.amazon.com/gp/feature.html?ie=UTF8&docId='
' Please update kindlegen from Amazon\'s website.', 'warning') '1000765211">kindlegen</a> is outdated! Creating MOBI might fail.'
' Please update <a href="http://www.amazon.com/gp/feature.html?ie=UTF8&docId='
'1000765211">kindlegen</a> from Amazon\'s website.', 'warning')
break break
else: else:
self.KindleGen = False self.KindleGen = False
formats = ['EPUB', 'CBZ'] formats = ['EPUB', 'CBZ']
self.addMessage('Cannot find kindlegen in PATH! MOBI creation will be disabled.', 'warning') self.addMessage('Cannot find <a href="http://www.amazon.com/gp/feature.html?ie=UTF8&docId='
if call('unrar', stdout=PIPE, stderr=STDOUT, shell=True) == 0: '1000765211">kindlegen</a> in PATH! MOBI creation will be disabled.', 'warning')
rarExitCode = call('unrar', stdout=PIPE, stderr=STDOUT, shell=True)
if rarExitCode == 0 or rarExitCode == 7:
self.UnRAR = True self.UnRAR = True
else: else:
self.UnRAR = False self.UnRAR = False
self.addMessage('Cannot find UnRAR! Processing of CBR/RAR files will be disabled.', 'warning') self.addMessage('Cannot find <a href="http://www.rarlab.com/rar_add.htm">UnRAR</a>!'
' Processing of CBR/RAR files will be disabled.', 'warning')
GUI.BasicModeButton.clicked.connect(self.modeBasic) GUI.BasicModeButton.clicked.connect(self.modeBasic)
GUI.AdvModeButton.clicked.connect(self.modeAdvanced) GUI.AdvModeButton.clicked.connect(self.modeAdvanced)
@@ -435,6 +579,9 @@ class Ui_KCC(object):
GUI.FileButton.clicked.connect(self.selectFile) GUI.FileButton.clicked.connect(self.selectFile)
GUI.ConvertButton.clicked.connect(self.convertStart) GUI.ConvertButton.clicked.connect(self.convertStart)
GUI.GammaSlider.valueChanged.connect(self.changeGamma) GUI.GammaSlider.valueChanged.connect(self.changeGamma)
GUI.NoRotateBox.stateChanged.connect(self.toggleNoSplitRotate)
GUI.UpscaleBox.stateChanged.connect(self.toggleUpscale)
GUI.StretchBox.stateChanged.connect(self.toggleStretch)
GUI.DeviceBox.activated.connect(self.changeDevice) GUI.DeviceBox.activated.connect(self.changeDevice)
KCC.connect(self.worker, QtCore.SIGNAL("progressBarTick"), self.updateProgressbar) KCC.connect(self.worker, QtCore.SIGNAL("progressBarTick"), self.updateProgressbar)
KCC.connect(self.worker, QtCore.SIGNAL("modeConvert"), self.modeConvert) KCC.connect(self.worker, QtCore.SIGNAL("modeConvert"), self.modeConvert)
@@ -477,4 +624,5 @@ class Ui_KCC(object):
self.modeExpert() self.modeExpert()
self.versionCheck.start() self.versionCheck.start()
self.hideProgressBar() self.hideProgressBar()
self.changeDevice(self.lastDevice, True) self.changeDevice(self.lastDevice)
self.worker.sync()

View File

@@ -2,8 +2,8 @@
# Form implementation generated from reading ui file 'KCC.ui' # Form implementation generated from reading ui file 'KCC.ui'
# #
# Created: Fri Jun 21 18:23:19 2013 # Created: Thu Jul 04 15:30:15 2013
# by: PyQt4 UI code generator 4.10.1 # by: PyQt4 UI code generator 4.10.2
# #
# WARNING! All changes made in this file will be lost! # WARNING! All changes made in this file will be lost!
@@ -47,6 +47,7 @@ class Ui_KCC(object):
self.OptionsAdvanced.setFont(font) self.OptionsAdvanced.setFont(font)
self.OptionsAdvanced.setObjectName(_fromUtf8("OptionsAdvanced")) self.OptionsAdvanced.setObjectName(_fromUtf8("OptionsAdvanced"))
self.gridLayout = QtGui.QGridLayout(self.OptionsAdvanced) self.gridLayout = QtGui.QGridLayout(self.OptionsAdvanced)
self.gridLayout.setContentsMargins(9, -1, -1, -1)
self.gridLayout.setObjectName(_fromUtf8("gridLayout")) self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
self.ProcessingBox = QtGui.QCheckBox(self.OptionsAdvanced) self.ProcessingBox = QtGui.QCheckBox(self.OptionsAdvanced)
self.ProcessingBox.setFocusPolicy(QtCore.Qt.NoFocus) self.ProcessingBox.setFocusPolicy(QtCore.Qt.NoFocus)

View File

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

View File

@@ -17,7 +17,7 @@
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE. # PERFORMANCE OF THIS SOFTWARE.
# #
__version__ = '3.0' __version__ = '3.1'
__license__ = 'ISC' __license__ = 'ISC'
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>' __copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
@@ -329,13 +329,13 @@ def applyImgOptimization(img, isSplit, toRight, options, overrideQuality=5):
img.cropWhiteSpace(10.0) img.cropWhiteSpace(10.0)
if options.cutpagenumbers: if options.cutpagenumbers:
img.cutPageNumber() img.cutPageNumber()
img.optimizeImage(options.gamma)
if overrideQuality != 5: if overrideQuality != 5:
img.resizeImage(options.upscale, options.stretch, options.black_borders, isSplit, toRight, img.resizeImage(options.upscale, options.stretch, options.black_borders, isSplit, toRight,
options.landscapemode, overrideQuality) options.landscapemode, overrideQuality)
else: else:
img.resizeImage(options.upscale, options.stretch, options.black_borders, isSplit, toRight, img.resizeImage(options.upscale, options.stretch, options.black_borders, isSplit, toRight,
options.landscapemode, options.quality) options.landscapemode, options.quality)
img.optimizeImage(options.gamma)
if options.forcepng and not options.forcecolor: if options.forcepng and not options.forcecolor:
img.quantizeImage() img.quantizeImage()
@@ -364,6 +364,10 @@ def dirImgProcess(path):
queue.get(True, 1) queue.get(True, 1)
except: except:
pass pass
if not GUI.conversionAlive:
pool.terminate()
rmtree(path)
raise UserWarning("Conversion interrupted.")
GUI.emit(QtCore.SIGNAL("progressBarTick")) GUI.emit(QtCore.SIGNAL("progressBarTick"))
pool.join() pool.join()
queue.close() queue.close()
@@ -379,6 +383,9 @@ def dirImgProcess(path):
splitCount += 1 splitCount += 1
pagenumbermodifier += 1 pagenumbermodifier += 1
pagenumbermodifier += 1 pagenumbermodifier += 1
else:
rmtree(path)
raise UserWarning("Source directory is empty.")
def fileImgProcess_init(queue, options): def fileImgProcess_init(queue, options):
@@ -682,8 +689,8 @@ def main(argv=None, qtGUI=None):
usage = "Usage: %prog [options] comic_file|comic_folder" usage = "Usage: %prog [options] comic_file|comic_folder"
parser = OptionParser(usage=usage, version=__version__) parser = OptionParser(usage=usage, version=__version__)
parser.add_option("-p", "--profile", action="store", dest="profile", default="KHD", parser.add_option("-p", "--profile", action="store", dest="profile", default="KHD",
help="Device profile (Choose one among K1, K2, K3, K4NT, K4T, KDX, KDXG, KHD, KF, KFHD, KFHD8) " help="Device profile (Choose one among K1, K2, K3, K4NT, K4T, KDX, KDXG, KHD, KF, KFHD, KFHD8,"
"[Default=KHD]") " KFA) [Default=KHD]")
parser.add_option("-t", "--title", action="store", dest="title", default="defaulttitle", parser.add_option("-t", "--title", action="store", dest="title", default="defaulttitle",
help="Comic title [Default=filename]") help="Comic title [Default=filename]")
parser.add_option("-m", "--manga-style", action="store_true", dest="righttoleft", default=False, parser.add_option("-m", "--manga-style", action="store_true", dest="righttoleft", default=False,
@@ -816,6 +823,10 @@ def checkOptions():
options.landscapemode = False options.landscapemode = False
options.panelview = False options.panelview = False
options.quality = 0 options.quality = 0
# Kindle for Android profile require target resolution.
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)
# Override profile data # Override profile data
if options.customwidth != 0 or options.customheight != 0: if options.customwidth != 0 or options.customheight != 0:
X = image.ProfileData.Profiles[options.profile][1][0] X = image.ProfileData.Profiles[options.profile][1][0]

View File

@@ -85,6 +85,7 @@ class ProfileData:
'KF': ("Kindle Fire", (600, 1024), Palette16, 1.0, (900, 1536)), 'KF': ("Kindle Fire", (600, 1024), Palette16, 1.0, (900, 1536)),
'KFHD': ("Kindle Fire HD 7\"", (800, 1280), Palette16, 1.0, (1200, 1920)), 'KFHD': ("Kindle Fire HD 7\"", (800, 1280), Palette16, 1.0, (1200, 1920)),
'KFHD8': ("Kindle Fire HD 8.9\"", (1200, 1920), Palette16, 1.0, (1800, 2880)), 'KFHD8': ("Kindle Fire HD 8.9\"", (1200, 1920), Palette16, 1.0, (1800, 2880)),
'KFA': ("Kindle for Android", (0, 0), Palette16, 1.0, (0, 0)),
'OTHER': ("Other", (0, 0), Palette16, 1.8, (0, 0)), 'OTHER': ("Other", (0, 0), Palette16, 1.8, (0, 0)),
} }
@@ -100,6 +101,7 @@ class ProfileData:
"Kindle Fire": 'KF', "Kindle Fire": 'KF',
"Kindle Fire HD 7\"": 'KFHD', "Kindle Fire HD 7\"": 'KFHD',
"Kindle Fire HD 8.9\"": 'KFHD8', "Kindle Fire HD 8.9\"": 'KFHD8',
"Kindle for Android": 'KFA',
"Other": 'OTHER' "Other": 'OTHER'
} }

View File

@@ -10,7 +10,7 @@ Usage (Windows):
from sys import platform from sys import platform
NAME = "KindleComicConverter" NAME = "KindleComicConverter"
VERSION = "3.0" VERSION = "3.1"
MAIN = "kcc.py" MAIN = "kcc.py"
if platform == "darwin": if platform == "darwin":