1
0
mirror of https://github.com/ciromattia/kcc synced 2026-04-17 22:48:53 +00:00

Compare commits

..

19 Commits
4.1 ... 4.2.1

Author SHA1 Message Date
Paweł Jastrzębski
56f23ab488 Merge pull request #108 from ciromattia/4.x
4.2.1
2014-08-03 11:22:28 +02:00
Paweł Jastrzębski
996af59e00 Updated README + version bump 2014-08-03 11:21:43 +02:00
Paweł Jastrzębski
37aa84c4aa Fixed MOBI processing anomalies 2014-08-02 07:54:15 +02:00
Paweł Jastrzębski
50574632e6 Replaced margin color detection algorithm 2014-08-01 07:23:55 +02:00
Paweł Jastrzębski
0afb9e8c0b Kindle: Fixed high quality mode (close #106) 2014-07-31 21:49:03 +02:00
Paweł Jastrzębski
7511c7eed6 Kindle DX: Changed default output format to CBZ 2014-07-29 19:59:21 +02:00
Paweł Jastrzębski
836a4146f9 MCD: Fixed small bug 2014-07-23 20:55:31 +02:00
Paweł Jastrzębski
15a240ccea Merge pull request #103 from ciromattia/4.x
Version 4.2
2014-07-18 10:29:14 +02:00
Paweł Jastrzębski
0722ddf8b0 Updated README + version bump 2014-07-18 08:45:57 +02:00
Paweł Jastrzębski
b3159b94e7 Prevented hypothetical problems with batch processing 2014-07-18 08:24:12 +02:00
Paweł Jastrzębski
ef5207c990 Dropped Windows XP support 2014-07-10 19:11:04 +02:00
Paweł Jastrzębski
db77d89817 Fixed Other profile 2014-07-05 09:38:10 +02:00
Paweł Jastrzębski
4571fadadb Resolved problems with page order on Kobo 2014-07-04 09:59:21 +02:00
Paweł Jastrzębski
94f56238ae Corruption detection now also delete non-image files (close #99) 2014-07-03 18:16:57 +02:00
Paweł Jastrzębski
5efb5d6dbb Updated Pillow (close #95) 2014-07-03 18:16:57 +02:00
Paweł Jastrzębski
623f615dd9 Added Manga Cover Database support 2014-07-03 18:16:56 +02:00
Paweł Jastrzębski
39fbbc42b3 Made KindleGen detection more foolproof 2014-07-03 18:16:56 +02:00
Paweł Jastrzębski
99405ab8a6 Disabled ultra quality mode for CBZ format 2014-07-03 18:16:55 +02:00
Paweł Jastrzębski
aadfca8306 Code cleanup 2014-07-03 18:16:54 +02:00
12 changed files with 660 additions and 617 deletions

View File

@@ -26,7 +26,7 @@ If you find **KCC** valuable you can consider donating to the authors:
## BINARY RELEASES ## BINARY RELEASES
You can find the latest released binary at the following links: You can find the latest released binary at the following links:
- **Windows:** [http://kcc.iosphe.re/Windows/](http://kcc.iosphe.re/Windows/) - **Windows (Vista or newer):** [http://kcc.iosphe.re/Windows/](http://kcc.iosphe.re/Windows/)
- **Linux:** [http://kcc.iosphe.re/Linux/](http://kcc.iosphe.re/Linux/) - **Linux:** [http://kcc.iosphe.re/Linux/](http://kcc.iosphe.re/Linux/)
- **OS X (10.8+):** [http://kcc.iosphe.re/OSX/](http://kcc.iosphe.re/OSX/) - **OS X (10.8+):** [http://kcc.iosphe.re/OSX/](http://kcc.iosphe.re/OSX/)
@@ -46,7 +46,7 @@ You can find the latest released binary at the following links:
### For running from source: ### For running from source:
- Python 3.3+ - Python 3.3+
- [PyQt5](http://www.riverbankcomputing.co.uk/software/pyqt/download5) 5.2.0+ - [PyQt5](http://www.riverbankcomputing.co.uk/software/pyqt/download5) 5.2.0+
- [Pillow](http://pypi.python.org/pypi/Pillow/) 2.3.0+ - [Pillow](http://pypi.python.org/pypi/Pillow/) 2.5.0+
- [psutil](https://pypi.python.org/pypi/psutil) 2.0+ - [psutil](https://pypi.python.org/pypi/psutil) 2.0+
- [python-slugify](http://pypi.python.org/pypi/python-slugify) - [python-slugify](http://pypi.python.org/pypi/python-slugify)
@@ -354,6 +354,20 @@ The app relies and includes the following scripts/binaries:
* Fixed _No optimization_ mode * Fixed _No optimization_ mode
* Multiple small tweaks nad minor bug fixes * Multiple small tweaks nad minor bug fixes
####4.2:
* Added [Manga Cover Database](http://manga.joentjuh.nl/) support
* Officially dropped Windows XP support
* Fixed _Other_ profile
* Fixed problems with page order on stock KOBO CBZ reader
* Many other small bug fixes and tweaks
####4.2.1:
* Improved margin color detection
* Fixed random crashes of MOBI processing step
* Fixed resizing problems in high quality mode
* Fixed some MCD support bugs
* Default output format for Kindle DX is now CBZ
## KNOWN ISSUES ## KNOWN ISSUES
Please check [wiki page](https://github.com/ciromattia/kcc/wiki/Known-issues). Please check [wiki page](https://github.com/ciromattia/kcc/wiki/Known-issues).

View File

@@ -18,7 +18,7 @@
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE. # PERFORMANCE OF THIS SOFTWARE.
__version__ = '4.1' __version__ = '4.2.1'
__license__ = 'ISC' __license__ = 'ISC'
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>' __copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
@@ -40,10 +40,10 @@ except ImportError:
try: try:
# noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences
import PIL import PIL
if tuple(map(int, ('2.3.0'.split(".")))) > tuple(map(int, (PIL.PILLOW_VERSION.split(".")))): if tuple(map(int, ('2.5.0'.split(".")))) > tuple(map(int, (PIL.PILLOW_VERSION.split(".")))):
missing.append('Pillow 2.3.0+') missing.append('Pillow 2.5.0+')
except ImportError: except ImportError:
missing.append('Pillow 2.3.0+') missing.append('Pillow 2.5.0+')
try: try:
# noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences
import slugify import slugify
@@ -63,10 +63,10 @@ if len(missing) > 0:
exit(1) exit(1)
from multiprocessing import freeze_support from multiprocessing import freeze_support
from kcc.comic2ebook import main, Copyright from kcc.comic2ebook import main
if __name__ == "__main__": if __name__ == "__main__":
freeze_support() freeze_support()
Copyright() print(('comic2ebook v%(__version__)s. Written by Ciro Mattia Gonano and Pawel Jastrzebski.' % globals()))
main(sys.argv[1:]) main(sys.argv[1:])
sys.exit(0) sys.exit(0)

View File

@@ -18,7 +18,7 @@
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE. # PERFORMANCE OF THIS SOFTWARE.
__version__ = '4.1' __version__ = '4.2.1'
__license__ = 'ISC' __license__ = 'ISC'
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>' __copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
@@ -33,10 +33,10 @@ missing = []
try: try:
# noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences
import PIL import PIL
if tuple(map(int, ('2.3.0'.split(".")))) > tuple(map(int, (PIL.PILLOW_VERSION.split(".")))): if tuple(map(int, ('2.5.0'.split(".")))) > tuple(map(int, (PIL.PILLOW_VERSION.split(".")))):
missing.append('Pillow 2.3.0+') missing.append('Pillow 2.5.0+')
except ImportError: except ImportError:
missing.append('Pillow 2.3.0+') missing.append('Pillow 2.5.0+')
if len(missing) > 0: if len(missing) > 0:
try: try:
# noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences
@@ -51,10 +51,10 @@ if len(missing) > 0:
exit(1) exit(1)
from multiprocessing import freeze_support from multiprocessing import freeze_support
from kcc.comic2panel import main, Copyright from kcc.comic2panel import main
if __name__ == "__main__": if __name__ == "__main__":
freeze_support() freeze_support()
Copyright() print(('comic2ebook v%(__version__)s. Written by Ciro Mattia Gonano and Pawel Jastrzebski.' % globals()))
main(sys.argv[1:]) main(sys.argv[1:])
sys.exit(0) sys.exit(0)

View File

@@ -1,5 +1,5 @@
#define MyAppName "Kindle Comic Converter" #define MyAppName "Kindle Comic Converter"
#define MyAppVersion "4.1" #define MyAppVersion "4.2.1"
#define MyAppPublisher "Ciro Mattia Gonano, Paweł Jastrzębski" #define MyAppPublisher "Ciro Mattia Gonano, Paweł Jastrzębski"
#define MyAppURL "http://kcc.iosphe.re/" #define MyAppURL "http://kcc.iosphe.re/"
#define MyAppExeName "KCC.exe" #define MyAppExeName "KCC.exe"
@@ -30,6 +30,7 @@ UninstallDisplayIcon={app}\{#MyAppExeName}
ChangesAssociations=True ChangesAssociations=True
InfoAfterFile=other\InstallWarning.rtf InfoAfterFile=other\InstallWarning.rtf
SignTool=SignTool /d $q{#MyAppName}$q /du $q{#MyAppURL}$q $f SignTool=SignTool /d $q{#MyAppName}$q /du $q{#MyAppURL}$q $f
MinVersion=0,6.0
[Languages] [Languages]
Name: "english"; MessagesFile: "compiler:Default.isl" Name: "english"; MessagesFile: "compiler:Default.isl"

8
kcc.py
View File

@@ -18,7 +18,7 @@
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE. # PERFORMANCE OF THIS SOFTWARE.
__version__ = '4.1' __version__ = '4.2.1'
__license__ = 'ISC' __license__ = 'ISC'
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>' __copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
@@ -47,10 +47,10 @@ except ImportError:
try: try:
# noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences
import PIL import PIL
if tuple(map(int, ('2.3.0'.split(".")))) > tuple(map(int, (PIL.PILLOW_VERSION.split(".")))): if tuple(map(int, ('2.5.0'.split(".")))) > tuple(map(int, (PIL.PILLOW_VERSION.split(".")))):
missing.append('Pillow 2.3.0+') missing.append('Pillow 2.5.0+')
except ImportError: except ImportError:
missing.append('Pillow 2.3.0+') missing.append('Pillow 2.5.0+')
try: try:
# noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences
import slugify import slugify

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__ = '4.1' __version__ = '4.2.1'
__license__ = 'ISC' __license__ = 'ISC'
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>' __copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
@@ -38,6 +38,7 @@ from xml.dom.minidom import parse
from html.parser import HTMLParser from html.parser import HTMLParser
from psutil import virtual_memory, Popen, Process from psutil import virtual_memory, Popen, Process
from uuid import uuid4 from uuid import uuid4
from copy import copy
from .shared import md5Checksum from .shared import md5Checksum
from . import comic2ebook from . import comic2ebook
from . import dualmetafix from . import dualmetafix
@@ -196,7 +197,6 @@ class VersionThread(QtCore.QThread):
def run(self): def run(self):
try: try:
sleep(1)
XML = urlopen('http://kcc.iosphe.re/Version.php') XML = urlopen('http://kcc.iosphe.re/Version.php')
XML = parse(XML) XML = parse(XML)
except Exception: except Exception:
@@ -422,9 +422,6 @@ class WorkerThread(QtCore.QThread):
if GUI.ColorBox.isChecked(): if GUI.ColorBox.isChecked():
options.forcecolor = True options.forcecolor = True
comic2ebook.options = options
comic2ebook.checkOptions()
for i in range(GUI.JobList.count()): for i in range(GUI.JobList.count()):
# Make sure that we don't consider any system message as job to do # Make sure that we don't consider any system message as job to do
if GUI.JobList.item(i).icon().isNull(): if GUI.JobList.item(i).icon().isNull():
@@ -446,7 +443,8 @@ class WorkerThread(QtCore.QThread):
jobargv = list(argv) jobargv = list(argv)
jobargv.append(job) jobargv.append(job)
try: try:
comic2ebook.options.title = 'defaulttitle' comic2ebook.options = copy(options)
comic2ebook.checkOptions()
outputPath = comic2ebook.makeBook(job, self) outputPath = comic2ebook.makeBook(job, self)
MW.hideProgressBar.emit() MW.hideProgressBar.emit()
except UserWarning as warn: except UserWarning as warn:
@@ -493,7 +491,8 @@ class WorkerThread(QtCore.QThread):
worker.signals.result.connect(self.addResult) worker.signals.result.connect(self.addResult)
self.pool.start(worker) self.pool.start(worker)
self.pool.waitForDone() self.pool.waitForDone()
sleep(0.5) while len(self.workerOutput) != len(outputPath):
sleep(0.1)
self.kindlegenErrorCode = [0] self.kindlegenErrorCode = [0]
for errors in self.workerOutput: for errors in self.workerOutput:
if errors[0] != 0: if errors[0] != 0:
@@ -503,7 +502,6 @@ class WorkerThread(QtCore.QThread):
for item in outputPath: for item in outputPath:
if os.path.exists(item): if os.path.exists(item):
os.remove(item) os.remove(item)
sleep(1)
if os.path.exists(item.replace('.epub', '.mobi')): if os.path.exists(item.replace('.epub', '.mobi')):
os.remove(item.replace('.epub', '.mobi')) os.remove(item.replace('.epub', '.mobi'))
self.clean() self.clean()
@@ -521,7 +519,8 @@ class WorkerThread(QtCore.QThread):
worker.signals.result.connect(self.addResult) worker.signals.result.connect(self.addResult)
self.pool.start(worker) self.pool.start(worker)
self.pool.waitForDone() self.pool.waitForDone()
sleep(0.5) while len(self.workerOutput) != len(outputPath):
sleep(0.1)
for success in self.workerOutput: for success in self.workerOutput:
if not success[0]: if not success[0]:
self.errors = True self.errors = True
@@ -555,7 +554,6 @@ class WorkerThread(QtCore.QThread):
for item in outputPath: for item in outputPath:
if os.path.exists(item): if os.path.exists(item):
os.remove(item) os.remove(item)
sleep(1)
if os.path.exists(item.replace('.epub', '.mobi')): if os.path.exists(item.replace('.epub', '.mobi')):
os.remove(item.replace('.epub', '.mobi')) os.remove(item.replace('.epub', '.mobi'))
MW.addMessage.emit('KindleGen failed to create MOBI!', 'error', False) MW.addMessage.emit('KindleGen failed to create MOBI!', 'error', False)
@@ -834,6 +832,9 @@ class KCCGUI(KCC_ui.Ui_KCC):
if value == 2 and 'Kobo' in str(GUI.DeviceBox.currentText()): if value == 2 and 'Kobo' in str(GUI.DeviceBox.currentText()):
self.addMessage('Kobo devices can\'t use ultra quality mode!', 'warning') self.addMessage('Kobo devices can\'t use ultra quality mode!', 'warning')
GUI.QualityBox.setCheckState(0) GUI.QualityBox.setCheckState(0)
elif value == 2 and 'CBZ' in str(GUI.FormatBox.currentText()):
self.addMessage('CBZ format don\'t support ultra quality mode!', 'warning')
GUI.QualityBox.setCheckState(0)
def changeGamma(self, value): def changeGamma(self, value):
value = float(value) value = float(value)
@@ -861,7 +862,7 @@ class KCCGUI(KCC_ui.Ui_KCC):
GUI.AdvModeButton.setEnabled(True) GUI.AdvModeButton.setEnabled(True)
if self.currentMode == 3: if self.currentMode == 3:
self.modeBasic() self.modeBasic()
self.changeFormat() self.changeFormat(event=False)
GUI.GammaSlider.setValue(0) GUI.GammaSlider.setValue(0)
self.changeGamma(0) self.changeGamma(0)
if profile['DefaultUpscale']: if profile['DefaultUpscale']:
@@ -870,19 +871,12 @@ class KCCGUI(KCC_ui.Ui_KCC):
self.addMessage('<a href="https://github.com/ciromattia/kcc/wiki/NonKindle-devices">' self.addMessage('<a href="https://github.com/ciromattia/kcc/wiki/NonKindle-devices">'
'List of supported Non-Kindle devices.</a>', 'info') 'List of supported Non-Kindle devices.</a>', 'info')
def changeFormat(self, outputFormat=None): def changeFormat(self, outputFormat=None, event=True):
profile = GUI.profiles[str(GUI.DeviceBox.currentText())] profile = GUI.profiles[str(GUI.DeviceBox.currentText())]
if outputFormat is not None: if outputFormat is not None:
GUI.FormatBox.setCurrentIndex(outputFormat) GUI.FormatBox.setCurrentIndex(outputFormat)
else: else:
if GUI.FormatBox.count() == 3: GUI.FormatBox.setCurrentIndex(profile['DefaultFormat'])
GUI.FormatBox.setCurrentIndex(profile['DefaultFormat'])
else:
if profile['DefaultFormat'] != 0:
tmpFormat = profile['DefaultFormat'] - 1
else:
tmpFormat = 0
GUI.FormatBox.setCurrentIndex(tmpFormat)
if GUI.WebtoonBox.isChecked(): if GUI.WebtoonBox.isChecked():
GUI.MangaBox.setEnabled(False) GUI.MangaBox.setEnabled(False)
GUI.QualityBox.setEnabled(False) GUI.QualityBox.setEnabled(False)
@@ -895,6 +889,10 @@ class KCCGUI(KCC_ui.Ui_KCC):
if GUI.ProcessingBox.isChecked(): if GUI.ProcessingBox.isChecked():
GUI.QualityBox.setEnabled(False) GUI.QualityBox.setEnabled(False)
GUI.QualityBox.setChecked(False) GUI.QualityBox.setChecked(False)
if event and GUI.QualityBox.isEnabled() and 'CBZ' in str(GUI.FormatBox.currentText()) and\
GUI.QualityBox.checkState() == 2:
self.addMessage('CBZ format don\'t support ultra quality mode!', 'warning')
GUI.QualityBox.setCheckState(0)
def stripTags(self, html): def stripTags(self, html):
s = HTMLStripper() s = HTMLStripper()
@@ -973,6 +971,15 @@ class KCCGUI(KCC_ui.Ui_KCC):
self.addMessage('Target resolution is not set!', 'error') self.addMessage('Target resolution is not set!', 'error')
self.needClean = True self.needClean = True
return return
if str(GUI.FormatBox.currentText()) == 'MOBI' and not GUI.KindleGen:
self.addMessage('Cannot find <a href="http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000765211">'
'<b>KindleGen</b></a>! MOBI conversion is not possible!', 'error')
if sys.platform.startswith('win'):
self.addMessage('Download it and place EXE in KCC directory.', 'error')
else:
self.addMessage('Download it, and place executable in /usr/local/bin directory.', 'error')
self.needClean = True
return
self.worker.start() self.worker.start()
def hideProgressBar(self): def hideProgressBar(self):
@@ -1118,7 +1125,7 @@ class KCCGUI(KCC_ui.Ui_KCC):
'DefaultUpscale': False, 'Label': 'KHD'}, 'DefaultUpscale': False, 'Label': 'KHD'},
"Kindle": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0, "Kindle": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
'DefaultUpscale': False, 'Label': 'K345'}, 'DefaultUpscale': False, 'Label': 'K345'},
"Kindle DX/DXG": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 0, "Kindle DX/DXG": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 2,
'DefaultUpscale': False, 'Label': 'KDX'}, 'DefaultUpscale': False, 'Label': 'KDX'},
"Kindle Fire": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0, "Kindle Fire": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
'DefaultUpscale': False, 'Label': 'KF'}, 'DefaultUpscale': False, 'Label': 'KF'},
@@ -1196,7 +1203,6 @@ class KCCGUI(KCC_ui.Ui_KCC):
kindleGenExitCode = Popen('kindlegen -locale en', stdout=PIPE, stderr=STDOUT, shell=True) kindleGenExitCode = Popen('kindlegen -locale en', stdout=PIPE, stderr=STDOUT, shell=True)
if kindleGenExitCode.wait() == 0: if kindleGenExitCode.wait() == 0:
self.KindleGen = True self.KindleGen = True
formats = ['MOBI', 'EPUB', 'CBZ']
versionCheck = Popen('kindlegen -locale en', stdout=PIPE, stderr=STDOUT, shell=True) versionCheck = Popen('kindlegen -locale en', stdout=PIPE, stderr=STDOUT, shell=True)
for line in versionCheck.stdout: for line in versionCheck.stdout:
line = line.decode("utf-8") line = line.decode("utf-8")
@@ -1210,13 +1216,6 @@ class KCCGUI(KCC_ui.Ui_KCC):
break break
else: else:
self.KindleGen = False self.KindleGen = False
formats = ['EPUB', 'CBZ']
if sys.platform.startswith('win'):
self.addMessage('Cannot find <a href="http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000765211">'
'kindlegen</a> in KCC directory! MOBI creation will be disabled.', 'warning')
else:
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 = Popen('unrar', stdout=PIPE, stderr=STDOUT, shell=True) rarExitCode = Popen('unrar', stdout=PIPE, stderr=STDOUT, shell=True)
rarExitCode = rarExitCode.wait() rarExitCode = rarExitCode.wait()
if rarExitCode == 0 or rarExitCode == 7: if rarExitCode == 0 or rarExitCode == 7:
@@ -1271,7 +1270,7 @@ class KCCGUI(KCC_ui.Ui_KCC):
GUI.DeviceBox.addItem(self.icons.deviceKobo, profile) GUI.DeviceBox.addItem(self.icons.deviceKobo, profile)
else: else:
GUI.DeviceBox.addItem(self.icons.deviceKindle, profile) GUI.DeviceBox.addItem(self.icons.deviceKindle, profile)
for f in formats: for f in ['MOBI', 'EPUB', 'CBZ']:
GUI.FormatBox.addItem(eval('self.icons.' + f + 'Format'), f) GUI.FormatBox.addItem(eval('self.icons.' + f + 'Format'), f)
if self.lastDevice > GUI.DeviceBox.count(): if self.lastDevice > GUI.DeviceBox.count():
self.lastDevice = 0 self.lastDevice = 0
@@ -1282,7 +1281,7 @@ class KCCGUI(KCC_ui.Ui_KCC):
GUI.DeviceBox.setCurrentIndex(self.lastDevice) GUI.DeviceBox.setCurrentIndex(self.lastDevice)
self.changeDevice() self.changeDevice()
if self.currentFormat != self.profiles[str(GUI.DeviceBox.currentText())]['DefaultFormat']: if self.currentFormat != self.profiles[str(GUI.DeviceBox.currentText())]['DefaultFormat']:
self.changeFormat(self.currentFormat) self.changeFormat(self.currentFormat, False)
for option in self.options: for option in self.options:
if str(option) == "customWidth": if str(option) == "customWidth":
GUI.customWidth.setText(str(self.options[option])) GUI.customWidth.setText(str(self.options[option]))

View File

@@ -1,4 +1,4 @@
__version__ = '4.1' __version__ = '4.2.1'
__license__ = 'ISC' __license__ = 'ISC'
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>' __copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'

File diff suppressed because it is too large Load Diff

View File

@@ -18,7 +18,7 @@
# PERFORMANCE OF THIS SOFTWARE. # PERFORMANCE OF THIS SOFTWARE.
# #
__version__ = '4.1' __version__ = '4.2.1'
__license__ = 'ISC' __license__ = 'ISC'
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>' __copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
@@ -36,7 +36,7 @@ except ImportError:
QtCore = None QtCore = None
def mergeDirectory_tick(output): def mergeDirectoryTick(output):
if output: if output:
mergeWorkerOutput.append(output) mergeWorkerOutput.append(output)
mergeWorkerPool.terminate() mergeWorkerPool.terminate()
@@ -108,7 +108,7 @@ def sanitizePanelSize(panel, opt):
return newPanels return newPanels
def splitImage_tick(output): def splitImageTick(output):
if output: if output:
splitWorkerOutput.append(output) splitWorkerOutput.append(output)
splitWorkerPool.terminate() splitWorkerPool.terminate()
@@ -207,10 +207,6 @@ def splitImage(work):
return str(sys.exc_info()[1]) return str(sys.exc_info()[1])
def Copyright():
print(('comic2panel v%(__version__)s. Written by Ciro Mattia Gonano and Pawel Jastrzebski.' % globals()))
def main(argv=None, qtGUI=None): def main(argv=None, qtGUI=None):
global options, GUI, splitWorkerPool, splitWorkerOutput, mergeWorkerPool, mergeWorkerOutput global options, GUI, splitWorkerPool, splitWorkerOutput, mergeWorkerPool, mergeWorkerOutput
parser = OptionParser(usage="Usage: kcc-c2p [options] comic_folder", add_help_option=False) parser = OptionParser(usage="Usage: kcc-c2p [options] comic_folder", add_help_option=False)
@@ -261,7 +257,7 @@ def main(argv=None, qtGUI=None):
GUI.progressBarTick.emit('Combining images') GUI.progressBarTick.emit('Combining images')
GUI.progressBarTick.emit(str(directoryNumer)) GUI.progressBarTick.emit(str(directoryNumer))
for i in mergeWork: for i in mergeWork:
mergeWorkerPool.apply_async(func=mergeDirectory, args=(i, ), callback=mergeDirectory_tick) mergeWorkerPool.apply_async(func=mergeDirectory, args=(i, ), callback=mergeDirectoryTick)
mergeWorkerPool.close() mergeWorkerPool.close()
mergeWorkerPool.join() mergeWorkerPool.join()
if GUI and not GUI.conversionAlive: if GUI and not GUI.conversionAlive:
@@ -284,7 +280,7 @@ def main(argv=None, qtGUI=None):
GUI.progressBarTick.emit('tick') GUI.progressBarTick.emit('tick')
if len(work) > 0: if len(work) > 0:
for i in work: for i in work:
splitWorkerPool.apply_async(func=splitImage, args=(i, ), callback=splitImage_tick) splitWorkerPool.apply_async(func=splitImage, args=(i, ), callback=splitImageTick)
splitWorkerPool.close() splitWorkerPool.close()
splitWorkerPool.join() splitWorkerPool.join()
if GUI and not GUI.conversionAlive: if GUI and not GUI.conversionAlive:

View File

@@ -16,11 +16,15 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
__version__ = '4.2.1'
__license__ = 'ISC' __license__ = 'ISC'
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>' __copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
import os import os
from io import BytesIO
from urllib.request import Request, urlopen
from urllib.parse import quote
from functools import reduce from functools import reduce
from PIL import Image, ImageOps, ImageStat, ImageChops from PIL import Image, ImageOps, ImageStat, ImageChops
from .shared import md5Checksum from .shared import md5Checksum
@@ -400,50 +404,44 @@ class ComicPage:
def getImageHistogram(self, image): def getImageHistogram(self, image):
histogram = image.histogram() histogram = image.histogram()
RBGW = [] if histogram[0] == 0:
pixelCount = 0
for i in range(256):
pixelCount += histogram[i] + histogram[256 + i] + histogram[512 + i]
RBGW.append(histogram[i] + histogram[256 + i] + histogram[512 + i])
white = 0
black = 0
for i in range(251, 256):
white += RBGW[i]
for i in range(5):
black += RBGW[i]
if black > pixelCount*0.8 and white == 0:
return 1
elif white > pixelCount*0.8 and black == 0:
return -1 return -1
elif histogram[255] == 0:
return 1
else: else:
return False return 0
def getImageFill(self, webtoon): def getImageFill(self):
fill = 0 bw = self.image.convert('L').point(lambda x: 0 if x < 128 else 255, '1')
if not webtoon and not self.rotated: imageBoxA = bw.getbbox()
# Search for horizontal solid lines imageBoxB = ImageChops.invert(bw).getbbox()
startY = 0 if imageBoxA is None or imageBoxB is None:
while startY < self.image.size[1]: surfaceB, surfaceW = 0, 0
if startY + 5 > self.image.size[1]:
startY = self.image.size[1] - 5
checkSolid = self.getImageHistogram(self.image.crop((0, startY, self.image.size[0], startY+5)))
if checkSolid:
fill += checkSolid
startY += 5
else: else:
# Search for vertical solid lines surfaceB = (imageBoxA[2] - imageBoxA[0]) * (imageBoxA[3] - imageBoxA[1])
startX = 0 surfaceW = (imageBoxB[2] - imageBoxB[0]) * (imageBoxB[3] - imageBoxB[1])
while startX < self.image.size[0]: if surfaceW < surfaceB:
if startX + 5 > self.image.size[0]: self.fill = 'white'
startX = self.image.size[0] - 5 elif surfaceW > surfaceB:
checkSolid = self.getImageHistogram(self.image.crop((startX, 0, startX+5, self.image.size[1])))
if checkSolid:
fill += checkSolid
startX += 5
if fill > 0:
self.fill = 'black' self.fill = 'black'
else: else:
self.fill = 'white' fill = 0
startY = 0
while startY < bw.size[1]:
if startY + 5 > bw.size[1]:
startY = bw.size[1] - 5
fill += self.getImageHistogram(bw.crop((0, startY, bw.size[0], startY+5)))
startY += 5
startX = 0
while startX < bw.size[0]:
if startX + 5 > bw.size[0]:
startX = bw.size[0] - 5
fill += self.getImageHistogram(bw.crop((startX, 0, startX+5, bw.size[1])))
startX += 5
if fill > 0:
self.fill = 'black'
else:
self.fill = 'white'
def isImageColor(self): def isImageColor(self):
v = ImageStat.Stat(self.image).var v = ImageStat.Stat(self.image).var
@@ -472,14 +470,37 @@ class ComicPage:
class Cover: class Cover:
def __init__(self, source, target): def __init__(self, source, target, opt, tomeNumber):
self.options = opt
self.source = source self.source = source
self.target = target self.target = target
self.image = Image.open(source) if tomeNumber == 0:
self.tomeNumber = 1
else:
self.tomeNumber = tomeNumber
if self.tomeNumber in self.options.remoteCovers:
try:
source = urlopen(Request(quote(self.options.remoteCovers[self.tomeNumber]).replace('%3A', ':', 1),
headers={'User-Agent': 'KindleComicConverter/' + __version__})).read()
self.image = Image.open(BytesIO(source))
self.processExternal()
except Exception:
self.image = Image.open(source)
self.processInternal()
else:
self.image = Image.open(source)
self.processInternal()
def processInternal(self):
self.image = self.image.convert('RGB') self.image = self.image.convert('RGB')
self.process() self.image = self.trim()
self.save() self.save()
def processExternal(self):
self.image = self.image.convert('RGB')
self.image.thumbnail(self.options.profileData[1], Image.ANTIALIAS)
self.save(True)
def trim(self): def trim(self):
bg = Image.new(self.image.mode, self.image.size, self.image.getpixel((0, 0))) bg = Image.new(self.image.mode, self.image.size, self.image.getpixel((0, 0)))
diff = ImageChops.difference(self.image, bg) diff = ImageChops.difference(self.image, bg)
@@ -490,12 +511,13 @@ class Cover:
else: else:
return self.image return self.image
def process(self): def save(self, external=False):
self.image = self.trim() if external:
source = self.options.remoteCovers[self.tomeNumber].split('/')[-1]
def save(self): else:
source = self.source
try: try:
if os.path.splitext(self.source)[1].lower() == '.png': if os.path.splitext(source)[1].lower() == '.png':
self.image.save(self.target, "PNG", optimize=1) self.image.save(self.target, "PNG", optimize=1)
else: else:
self.image.save(self.target, "JPEG", optimize=1) self.image.save(self.target, "JPEG", optimize=1)

View File

@@ -14,7 +14,7 @@ if version_info[0] != 3:
exit(1) exit(1)
NAME = "KindleComicConverter" NAME = "KindleComicConverter"
VERSION = "4.1" VERSION = "4.2.1"
MAIN = "kcc.py" MAIN = "kcc.py"
if platform == "darwin": if platform == "darwin":

View File

@@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
# Linux Python package build script # Linux Python package build script
VERSION="4.1" VERSION="4.2.1"
cp kcc.py __main__.py cp kcc.py __main__.py
zip kcc.zip __main__.py kcc/*.py zip kcc.zip __main__.py kcc/*.py