From a7e4968836f86fd9177b2d45f32ed9d1506b6ec8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Jastrz=C4=99bski?= Date: Fri, 8 Nov 2013 15:11:33 +0100 Subject: [PATCH 1/4] GUI tweaks --- kcc/KCC_gui.py | 57 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/kcc/KCC_gui.py b/kcc/KCC_gui.py index d00f4dc..4c1c4d7 100644 --- a/kcc/KCC_gui.py +++ b/kcc/KCC_gui.py @@ -205,6 +205,30 @@ class VersionThread(QtCore.QThread): 'Changelog)', 'warning') +class ProgressThread(QtCore.QThread): + def __init__(self): + QtCore.QThread.__init__(self) + 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) @@ -296,6 +320,7 @@ class WorkerThread(QtCore.QThread): self.conversionAlive = GUIMain.conversionAlive def clean(self): + GUIMain.progress.content = '' GUIMain.needClean = True self.emit(QtCore.SIGNAL("hideProgressBar")) self.emit(QtCore.SIGNAL("addMessage"), 'Conversion interrupted.', 'error') @@ -359,9 +384,11 @@ class WorkerThread(QtCore.QThread): self.errors = False self.emit(QtCore.SIGNAL("addMessage"), 'Source: ' + 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') + GUIMain.progress.content = 'Creating CBZ files' else: - self.emit(QtCore.SIGNAL("addMessage"), 'Creating EPUB file...', 'info') + self.emit(QtCore.SIGNAL("addMessage"), 'Creating EPUB files', 'info') + GUIMain.progress.content = 'Creating EPUB files' jobargv = list(argv) jobargv.append(job) try: @@ -372,10 +399,12 @@ class WorkerThread(QtCore.QThread): self.clean() return else: + GUIMain.progress.content = '' self.errors = True self.emit(QtCore.SIGNAL("addMessage"), str(warn), 'warning') self.emit(QtCore.SIGNAL("addMessage"), 'Failed to create output file!', 'warning') except Exception as err: + GUIMain.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" @@ -388,15 +417,17 @@ class WorkerThread(QtCore.QThread): self.clean() return if not self.errors: + GUIMain.progress.content = '' if str(GUI.FormatBox.currentText()) == 'CBZ': - self.emit(QtCore.SIGNAL("addMessage"), 'Creating CBZ file... Done!', 'info', True) + self.emit(QtCore.SIGNAL("addMessage"), 'Creating CBZ files... Done!', 'info', True) else: - self.emit(QtCore.SIGNAL("addMessage"), 'Creating EPUB file... Done!', 'info', True) + self.emit(QtCore.SIGNAL("addMessage"), 'Creating EPUB files... Done!', 'info', True) if str(GUI.FormatBox.currentText()) == 'MOBI': 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 file...', 'info') + self.emit(QtCore.SIGNAL("addMessage"), 'Creating MOBI files', 'info') + GUIMain.progress.content = 'Creating MOBI files' self.workerOutput = [] # Number of KindleGen threads depends on the size of RAM self.pool.setMaxThreadCount(self.threadNumber) @@ -420,8 +451,10 @@ class WorkerThread(QtCore.QThread): self.clean() return if self.kindlegenErrorCode[0] == 0: - self.emit(QtCore.SIGNAL("addMessage"), 'Creating MOBI file... Done!', 'info', True) - self.emit(QtCore.SIGNAL("addMessage"), 'Cleaning MOBI file...', 'info') + GUIMain.progress.content = '' + self.emit(QtCore.SIGNAL("addMessage"), 'Creating MOBI files... Done!', 'info', True) + self.emit(QtCore.SIGNAL("addMessage"), 'Cleaning MOBI files', 'info') + GUIMain.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. @@ -438,13 +471,15 @@ class WorkerThread(QtCore.QThread): break if not self.errors: for item in outputPath: + GUIMain.progress.content = '' mobiPath = item.replace('.epub', '.mobi') os.remove(mobiPath + '_toclean') GUIMain.completedWork[os.path.basename(mobiPath).encode('utf-8')] = \ mobiPath.encode('utf-8') - self.emit(QtCore.SIGNAL("addMessage"), 'Cleaning MOBI file... Done!', 'info', + self.emit(QtCore.SIGNAL("addMessage"), 'Cleaning MOBI files... Done!', 'info', True) else: + GUIMain.progress.content = '' for item in outputPath: mobiPath = item.replace('.epub', '.mobi') if os.path.exists(mobiPath): @@ -453,6 +488,7 @@ class WorkerThread(QtCore.QThread): os.remove(mobiPath + '_toclean') self.emit(QtCore.SIGNAL("addMessage"), 'KindleUnpack failed to clean MOBI file!', 'error') else: + GUIMain.progress.content = '' epubSize = (os.path.getsize(self.kindlegenErrorCode[2]))/1024/1024 for item in outputPath: if os.path.exists(item): @@ -471,6 +507,7 @@ class WorkerThread(QtCore.QThread): else: for item in outputPath: GUIMain.completedWork[os.path.basename(item).encode('utf-8')] = item.encode('utf-8') + GUIMain.progress.content = '' self.emit(QtCore.SIGNAL("hideProgressBar")) GUIMain.needClean = True self.emit(QtCore.SIGNAL("addMessage"), 'All jobs completed.', 'info') @@ -796,6 +833,7 @@ class Ui_KCC(object): if not GUI.ConvertButton.isEnabled(): event.ignore() self.contentServer.stop() + self.progress.stop() self.settings.setValue('settingsVersion', __version__) self.settings.setValue('lastPath', self.lastPath) self.settings.setValue('lastDevice', GUI.DeviceBox.currentIndex()) @@ -868,6 +906,7 @@ class Ui_KCC(object): self.worker = WorkerThread() self.versionCheck = VersionThread() self.contentServer = WebServerThread() + self.progress = ProgressThread() self.conversionAlive = False self.needClean = True self.QualityBoxDisabled = False @@ -941,6 +980,7 @@ class Ui_KCC(object): KCC.connect(self.worker, QtCore.SIGNAL("hideProgressBar"), self.hideProgressBar) KCC.connect(self.versionCheck, QtCore.SIGNAL("addMessage"), self.addMessage) KCC.connect(self.contentServer, QtCore.SIGNAL("addMessage"), self.addMessage) + KCC.connect(self.progress, QtCore.SIGNAL("addMessage"), self.addMessage) KCC.closeEvent = self.saveSettings for f in formats: @@ -983,5 +1023,6 @@ class Ui_KCC(object): self.changeFormat() self.versionCheck.start() self.contentServer.start() + self.progress.start() self.hideProgressBar() self.worker.sync() From c8e5b7de9adb8ca773124ca302cc38265876208e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Jastrz=C4=99bski?= Date: Fri, 8 Nov 2013 16:55:43 +0100 Subject: [PATCH 2/4] Implemented new method to detect border color in non-webtoon comics --- kcc/comic2ebook.py | 9 +++-- kcc/image.py | 91 +++++++++++++++++++++++++++++++++------------- 2 files changed, 70 insertions(+), 30 deletions(-) diff --git a/kcc/comic2ebook.py b/kcc/comic2ebook.py index 2ee8155..b33156d 100755 --- a/kcc/comic2ebook.py +++ b/kcc/comic2ebook.py @@ -296,7 +296,8 @@ def getImageFileName(imgfile): def applyImgOptimization(img, opt, overrideQuality=5): - img.getImageFill(opt.webtoon) + if not img.fill: + img.getImageFill(opt.webtoon) if not opt.webtoon: img.cropWhiteSpace(10.0) if opt.cutpagenumbers and not opt.webtoon: @@ -377,17 +378,17 @@ def fileImgProcess(work): applyImgOptimization(img1, opt) img1.saveToDir(dirpath, opt.forcepng, opt.forcecolor, wipe) if opt.quality == 2: - img3 = image.ComicPage(split[0], opt.profileData) + img3 = image.ComicPage(split[0], opt.profileData, img0.fill) applyImgOptimization(img3, opt, 0) img3.saveToDir(dirpath, opt.forcepng, opt.forcecolor, True) - img4 = image.ComicPage(split[1], opt.profileData) + img4 = image.ComicPage(split[1], opt.profileData, img1.fill) 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) + img2 = image.ComicPage(os.path.join(dirpath, afile), opt.profileData, img.fill) if img.rotated: img2.image = img2.image.rotate(90) img2.rotated = True diff --git a/kcc/image.py b/kcc/image.py index 3a3ed21..96f8396 100755 --- a/kcc/image.py +++ b/kcc/image.py @@ -142,7 +142,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: @@ -172,7 +172,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: @@ -428,7 +431,7 @@ class ComicPage: self.image = self.image.crop((0, 0, widthImg - diff, heightImg)) return self.image - def getImageHistogram(self, image): + def getImageHistogram(self, image, new=True): histogram = image.histogram() RBGW = [] pixelCount = 0 @@ -437,37 +440,73 @@ 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: + 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: + stopX = self.image.size[0] + searching = False + if fill > 0: self.fill = 'black' else: self.fill = 'white' \ No newline at end of file From 77066d7a9f55d2bb0ecabbbae2d297e05fe64257 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Jastrz=C4=99bski?= Date: Fri, 8 Nov 2013 17:04:34 +0100 Subject: [PATCH 3/4] Optimization of ProgressThread --- kcc/KCC_gui.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kcc/KCC_gui.py b/kcc/KCC_gui.py index 4c1c4d7..e473a3a 100644 --- a/kcc/KCC_gui.py +++ b/kcc/KCC_gui.py @@ -321,6 +321,7 @@ class WorkerThread(QtCore.QThread): def clean(self): GUIMain.progress.content = '' + self.progress.stop() GUIMain.needClean = True self.emit(QtCore.SIGNAL("hideProgressBar")) self.emit(QtCore.SIGNAL("addMessage"), 'Conversion interrupted.', 'error') @@ -508,6 +509,7 @@ class WorkerThread(QtCore.QThread): for item in outputPath: GUIMain.completedWork[os.path.basename(item).encode('utf-8')] = item.encode('utf-8') GUIMain.progress.content = '' + self.progress.stop() self.emit(QtCore.SIGNAL("hideProgressBar")) GUIMain.needClean = True self.emit(QtCore.SIGNAL("addMessage"), 'All jobs completed.', 'info') @@ -806,6 +808,7 @@ class Ui_KCC(object): self.conversionAlive = False self.worker.sync() else: + self.progress.start() if self.needClean: self.needClean = False GUI.JobList.clear() @@ -833,7 +836,6 @@ class Ui_KCC(object): if not GUI.ConvertButton.isEnabled(): event.ignore() self.contentServer.stop() - self.progress.stop() self.settings.setValue('settingsVersion', __version__) self.settings.setValue('lastPath', self.lastPath) self.settings.setValue('lastDevice', GUI.DeviceBox.currentIndex()) @@ -1023,6 +1025,5 @@ class Ui_KCC(object): self.changeFormat() self.versionCheck.start() self.contentServer.start() - self.progress.start() self.hideProgressBar() self.worker.sync() From c95a9395de17156f36a29f5459dcb0435dccf1f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Jastrz=C4=99bski?= Date: Fri, 8 Nov 2013 17:13:41 +0100 Subject: [PATCH 4/4] Optimization of ProgressThread --- kcc/KCC_gui.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kcc/KCC_gui.py b/kcc/KCC_gui.py index e473a3a..eef3ce9 100644 --- a/kcc/KCC_gui.py +++ b/kcc/KCC_gui.py @@ -321,7 +321,7 @@ class WorkerThread(QtCore.QThread): def clean(self): GUIMain.progress.content = '' - self.progress.stop() + GUIMain.progress.stop() GUIMain.needClean = True self.emit(QtCore.SIGNAL("hideProgressBar")) self.emit(QtCore.SIGNAL("addMessage"), 'Conversion interrupted.', 'error') @@ -509,7 +509,7 @@ class WorkerThread(QtCore.QThread): for item in outputPath: GUIMain.completedWork[os.path.basename(item).encode('utf-8')] = item.encode('utf-8') GUIMain.progress.content = '' - self.progress.stop() + GUIMain.progress.stop() self.emit(QtCore.SIGNAL("hideProgressBar")) GUIMain.needClean = True self.emit(QtCore.SIGNAL("addMessage"), 'All jobs completed.', 'info')