diff options
| -rw-r--r-- | README.md | 10 | ||||
| -rw-r--r-- | gui/KCC.ui | 62 | ||||
| -rwxr-xr-x | kcc-c2p.py | 2 | ||||
| -rw-r--r-- | kcc.iss | 2 | ||||
| -rwxr-xr-x | kcc.py | 2 | ||||
| -rw-r--r-- | kindlecomicconverter/KCC_gui.py | 25 | ||||
| -rw-r--r-- | kindlecomicconverter/KCC_ui.py | 7 | ||||
| -rw-r--r-- | kindlecomicconverter/__init__.py | 2 | ||||
| -rw-r--r-- | kindlecomicconverter/cbxarchive.py | 3 | ||||
| -rwxr-xr-x | kindlecomicconverter/comic2ebook.py | 27 | ||||
| -rw-r--r-- | kindlecomicconverter/comic2panel.py | 127 | ||||
| -rwxr-xr-x | kindlecomicconverter/image.py | 4 | ||||
| -rw-r--r-- | kindlecomicconverter/shared.py | 2 | ||||
| -rw-r--r-- | kindlecomicconverter/startup.py | 5 | ||||
| -rw-r--r-- | other/osx/Info.plist | 6 | ||||
| -rwxr-xr-x | setup.py | 22 |
16 files changed, 185 insertions, 123 deletions
diff --git a/README.md b/README.md index a06ad77..cbdd012 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # KCC -[]() []() []() +[](https://github.com/ciromattia/kcc/releases) [](https://pypi.python.org/pypi/KindleComicConverter) [](https://aur.archlinux.org/packages/kcc/) **Kindle Comic Converter** is a Python app to convert comic/manga files or folders to EPUB, Panel View MOBI or E-Ink optimized CBZ. It was initially developed for Kindle but since version 4.6 it outputs valid EPUB 3.0 so _**despite its name, KCC is @@ -72,7 +72,7 @@ After completed conversion you should find ready file alongside the original inp Please check [our wiki](https://github.com/ciromattia/kcc/wiki/) for more details. -CLI version of **KCC** is intended for power users. It is not idiot-proof like GUI :-) +CLI version of **KCC** is intended for power users. It allow to use options that might not be compatible and decrease quality of output. ### Standalone `kcc-c2e.py` usage: @@ -86,6 +86,7 @@ Options: KDX, KPW, KV, KoMT, KoG, KoGHD, KoA, KoAHD, KoAH2O, KoAO) [Default=KV] -m, --manga-style Manga style (right-to-left reading and splitting) + -q, --hq Try to increase the quality of magnification -2, --two-panel Display two not four panels in Panel View mode -w, --webtoon Webtoon processing mode @@ -170,6 +171,11 @@ The app relies and includes the following scripts: * [Kobo Aura ONE](http://kcc.iosphe.re/Samples/Ubunchu-KoAO.kepub.epub) ## CHANGELOG +#### 5.4: +* Reimplemented high quality Panel View option +* Improved webtoon splitter +* Fixed page splitter + #### 5.3.1: * Small increase of output quality * Improved error reporting diff --git a/gui/KCC.ui b/gui/KCC.ui index 5dc8697..56cc2b6 100644 --- a/gui/KCC.ui +++ b/gui/KCC.ui @@ -66,7 +66,16 @@ <bool>false</bool> </property> <layout class="QGridLayout" name="gridLayout_3"> - <property name="margin"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> <number>0</number> </property> <item row="0" column="2"> @@ -127,7 +136,16 @@ <item row="4" column="0" colspan="2"> <widget class="QWidget" name="optionWidget" native="true"> <layout class="QGridLayout" name="gridLayout_2"> - <property name="margin"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> <number>0</number> </property> <item row="0" column="0"> @@ -156,10 +174,13 @@ <item row="0" column="2"> <widget class="QCheckBox" name="qualityBox"> <property name="toolTip"> - <string><html><head/><body><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - 4 panels<br/></span>Zoom each corner separately.</p><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Checked - 2 panels<br/></span>Zoom only the top and bottom of the page.</p></body></html></string> + <string><html><head/><body><p style='white-space:pre'><span style=" font-weight:600; text-decoration: underline;">Unchecked - 4 panels<br/></span>Zoom each corner separately.</p><p style='white-space:pre'><span style=" font-weight:600; text-decoration: underline;">Indeterminate - 2 panels<br/></span>Zoom only the top and bottom of the page.</p><p><span style=" font-weight:600; text-decoration: underline;">Checked - 4 high quality panels<br/></span>Zoom each corner separately. Try to increase the quality of magnification. Check wiki for more details.</p></body></html></string> </property> <property name="text"> - <string>Panel View 4/2</string> + <string>Panel View 4/2/HQ</string> + </property> + <property name="tristate"> + <bool>true</bool> </property> </widget> </item> @@ -238,7 +259,16 @@ <bool>false</bool> </property> <layout class="QHBoxLayout" name="horizontalLayout_2"> - <property name="margin"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> <number>0</number> </property> <item> @@ -267,7 +297,16 @@ <item row="0" column="0" colspan="2"> <widget class="QWidget" name="toolWidget" native="true"> <layout class="QHBoxLayout" name="horizontalLayout"> - <property name="margin"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> <number>0</number> </property> <item> @@ -316,7 +355,16 @@ </sizepolicy> </property> <layout class="QGridLayout" name="gridLayout_4"> - <property name="margin"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> <number>0</number> </property> <item row="0" column="0"> diff --git a/kcc-c2p.py b/kcc-c2p.py index f1fb915..fca94fc 100755 --- a/kcc-c2p.py +++ b/kcc-c2p.py @@ -28,4 +28,4 @@ from kindlecomicconverter.startup import startC2P if __name__ == "__main__": freeze_support() - startC2P() \ No newline at end of file + startC2P() diff --git a/kcc.iss b/kcc.iss index 7dea76f..ba63491 100644 --- a/kcc.iss +++ b/kcc.iss @@ -1,5 +1,5 @@ #define MyAppName "Kindle Comic Converter" -#define MyAppVersion "5.3.1" +#define MyAppVersion "5.4" #define MyAppPublisher "Ciro Mattia Gonano, Paweł Jastrzębski" #define MyAppURL "http://kcc.iosphe.re/" #define MyAppExeName "KCC.exe" diff --git a/kcc.py b/kcc.py index 445b0a3..afd4796 100755 --- a/kcc.py +++ b/kcc.py @@ -39,7 +39,7 @@ elif sys.platform.startswith('win'): class _Popen(forking.Popen): def __init__(self, *args, **kw): if hasattr(sys, 'frozen'): - # noinspection PyProtectedMember + # noinspection PyUnresolvedReferences,PyProtectedMember os.putenv('_MEIPASS2', sys._MEIPASS) try: super(_Popen, self).__init__(*args, **kw) diff --git a/kindlecomicconverter/KCC_gui.py b/kindlecomicconverter/KCC_gui.py index 5cf29d7..5a3b538 100644 --- a/kindlecomicconverter/KCC_gui.py +++ b/kindlecomicconverter/KCC_gui.py @@ -254,8 +254,10 @@ class WorkerThread(QtCore.QThread): options.splitter = 2 elif GUI.rotateBox.checkState() == 2: options.splitter = 1 - if GUI.qualityBox.isChecked(): + if GUI.qualityBox.checkState() == 1: options.autoscale = True + elif GUI.qualityBox.checkState() == 2: + options.hq = True if GUI.webtoonBox.isChecked(): options.webtoon = True if GUI.upscaleBox.checkState() == 1: @@ -531,8 +533,8 @@ class KCCGUI(KCC_ui.Ui_mainWindow): def clearJobs(self): GUI.jobList.clear() - # noinspection PyCallByClass,PyTypeChecker def openWiki(self): + # noinspection PyCallByClass QtGui.QDesktopServices.openUrl(QtCore.QUrl('https://github.com/ciromattia/kcc/wiki')) def modeChange(self, mode): @@ -613,6 +615,18 @@ class KCCGUI(KCC_ui.Ui_mainWindow): GUI.rotateBox.setEnabled(True) GUI.upscaleBox.setEnabled(True) + def togglequalityBox(self, value): + profile = GUI.profiles[str(GUI.deviceBox.currentText())] + if value == 2: + if profile['Label'] in ['KV']: + self.addMessage('This option is intended for older Kindle models.', 'warning') + self.addMessage('It might not provide any quality increase in this case.', 'warning') + GUI.upscaleBox.setEnabled(False) + GUI.upscaleBox.setChecked(True) + else: + GUI.upscaleBox.setEnabled(True) + GUI.upscaleBox.setChecked(profile['DefaultUpscale']) + def changeGamma(self, value): valueRaw = int(5 * round(float(value) / 5)) value = '%.2f' % (float(valueRaw) / 100) @@ -634,7 +648,8 @@ class KCCGUI(KCC_ui.Ui_mainWindow): self.changeFormat() GUI.gammaSlider.setValue(0) self.changeGamma(0) - GUI.qualityBox.setEnabled(profile['PVOptions']) + if not GUI.webtoonBox.isChecked(): + GUI.qualityBox.setEnabled(profile['PVOptions']) GUI.upscaleBox.setChecked(profile['DefaultUpscale']) if not profile['PVOptions']: GUI.qualityBox.setChecked(False) @@ -648,7 +663,8 @@ class KCCGUI(KCC_ui.Ui_mainWindow): GUI.formatBox.setCurrentIndex(outputFormat) else: GUI.formatBox.setCurrentIndex(profile['DefaultFormat']) - GUI.qualityBox.setEnabled(profile['PVOptions']) + if not GUI.webtoonBox.isChecked(): + GUI.qualityBox.setEnabled(profile['PVOptions']) if str(GUI.formatBox.currentText()) == 'MOBI/AZW3': GUI.outputSplit.setEnabled(True) else: @@ -1002,6 +1018,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow): GUI.gammaSlider.valueChanged.connect(self.changeGamma) GUI.gammaBox.stateChanged.connect(self.togglegammaBox) GUI.webtoonBox.stateChanged.connect(self.togglewebtoonBox) + GUI.qualityBox.stateChanged.connect(self.togglequalityBox) GUI.deviceBox.activated.connect(self.changeDevice) GUI.formatBox.activated.connect(self.changeFormat) MW.progressBarTick.connect(self.updateProgressbar) diff --git a/kindlecomicconverter/KCC_ui.py b/kindlecomicconverter/KCC_ui.py index 71689ab..b23c981 100644 --- a/kindlecomicconverter/KCC_ui.py +++ b/kindlecomicconverter/KCC_ui.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'gui\KCC.ui' # -# Created by: PyQt5 UI code generator 5.6 +# Created by: PyQt5 UI code generator 5.8.1 # # WARNING! All changes made in this file will be lost! @@ -81,6 +81,7 @@ class Ui_mainWindow(object): self.rotateBox.setObjectName("rotateBox") self.gridLayout_2.addWidget(self.rotateBox, 0, 1, 1, 1) self.qualityBox = QtWidgets.QCheckBox(self.optionWidget) + self.qualityBox.setTristate(True) self.qualityBox.setObjectName("qualityBox") self.gridLayout_2.addWidget(self.qualityBox, 0, 2, 1, 1) self.webtoonBox = QtWidgets.QCheckBox(self.optionWidget) @@ -241,8 +242,8 @@ class Ui_mainWindow(object): self.mangaBox.setText(_translate("mainWindow", "Manga mode")) self.rotateBox.setToolTip(_translate("mainWindow", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Split<br/></span>Double page spreads will be cut into two separate pages.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Rotate and split<br/></span>Double page spreads will be displayed twice. First rotated and then split. </p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Rotate<br/></span>Double page spreads will be rotated.</p></body></html>")) self.rotateBox.setText(_translate("mainWindow", "Spread splitter")) - self.qualityBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - 4 panels<br/></span>Zoom each corner separately.</p><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Checked - 2 panels<br/></span>Zoom only the top and bottom of the page.</p></body></html>")) - self.qualityBox.setText(_translate("mainWindow", "Panel View 4/2")) + self.qualityBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - 4 panels<br/></span>Zoom each corner separately.</p><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - 2 panels<br/></span>Zoom only the top and bottom of the page.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - 4 high quality panels<br/></span>Zoom each corner separately. Try to increase the quality of magnification. Check wiki for more details.</p></body></html>")) + self.qualityBox.setText(_translate("mainWindow", "Panel View 4/2/HQ")) self.webtoonBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Enable special parsing mode for Korean Webtoons.</p></body></html>")) self.webtoonBox.setText(_translate("mainWindow", "Webtoon mode")) self.upscaleBox.setToolTip(_translate("mainWindow", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Nothing<br/></span>Images smaller than device resolution will not be resized.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Stretching<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be not preserved.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Upscaling<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be preserved.</p></body></html>")) diff --git a/kindlecomicconverter/__init__.py b/kindlecomicconverter/__init__.py index 3622f15..a873448 100644 --- a/kindlecomicconverter/__init__.py +++ b/kindlecomicconverter/__init__.py @@ -1,4 +1,4 @@ -__version__ = '5.3.1' +__version__ = '5.4' __license__ = 'ISC' __copyright__ = '2012-2017, Ciro Mattia Gonano <[email protected]>, Pawel Jastrzebski <[email protected]>' __docformat__ = 'restructuredtext en' diff --git a/kindlecomicconverter/cbxarchive.py b/kindlecomicconverter/cbxarchive.py index 7bd833f..7aba70f 100644 --- a/kindlecomicconverter/cbxarchive.py +++ b/kindlecomicconverter/cbxarchive.py @@ -16,12 +16,11 @@ # PERFORMANCE OF THIS SOFTWARE. # -import sys import os from zipfile import is_zipfile, ZipFile from subprocess import STDOUT, PIPE from psutil import Popen -from shutil import move, copy +from shutil import move from . import rarfile from .shared import check7ZFile as is_7zfile diff --git a/kindlecomicconverter/comic2ebook.py b/kindlecomicconverter/comic2ebook.py index f5c6320..1bffcc4 100755 --- a/kindlecomicconverter/comic2ebook.py +++ b/kindlecomicconverter/comic2ebook.py @@ -103,6 +103,10 @@ def buildHTML(path, imgfile, imgfilepath): os.makedirs(htmlpath) htmlfile = os.path.join(htmlpath, filename[0] + '.xhtml') imgsize = Image.open(os.path.join(head, "Images", postfix, imgfile)).size + if options.hq: + imgsizeframe = deviceres + else: + imgsizeframe = imgsize f = open(htmlfile, "w", encoding='UTF-8') f.writelines(["<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", "<!DOCTYPE html>\n", @@ -111,17 +115,20 @@ def buildHTML(path, imgfile, imgfilepath): "<title>", escape(filename[0]), "</title>\n", "<link href=\"", "../" * (backref - 1), "style.css\" type=\"text/css\" rel=\"stylesheet\"/>\n", "<meta name=\"viewport\" " - "content=\"width=" + str(deviceres[0]) + ", height=" + str(deviceres[1]) + "\"/>\n" + "content=\"width=" + str(imgsize[0]) + ", height=" + str(imgsize[1]) + "\"/>\n" "</head>\n", "<body style=\"" + additionalStyle + "\">\n", "<div style=\"text-align:center;top:" + getTopMargin(deviceres, imgsize) + "%;\">\n", - "<img width=\"" + str(imgsize[0]) + "\" height=\"" + str(imgsize[1]) + "\" ", + "<img width=\"" + str(imgsizeframe[0]) + "\" height=\"" + str(imgsizeframe[1]) + "\" ", "src=\"", "../" * backref, "Images/", postfix, imgfile, "\"/>\n</div>\n"]) if options.iskindle and options.panelview: if options.autoscale: size = (getPanelViewResolution(imgsize, deviceres)) else: - size = (int(imgsize[0] * 1.5), int(imgsize[1] * 1.5)) + if options.hq: + size = imgsize + else: + size = (int(imgsize[0] * 1.5), int(imgsize[1] * 1.5)) if size[0] - deviceres[0] < deviceres[0] * 0.01: noHorizontalPV = True else: @@ -455,7 +462,7 @@ def buildEPUB(path, chapterNames, tomeNumber): def imgDirectoryProcessing(path): global workerPool, workerOutput - workerPool = Pool() + workerPool = Pool(maxtasksperchild=100) workerOutput = [] options.imgMetadata = {} options.imgOld = [] @@ -884,6 +891,8 @@ def makeParser(): " KoA, KoAHD, KoAH2O, KoAO) [Default=KV]") mainOptions.add_option("-m", "--manga-style", action="store_true", dest="righttoleft", default=False, help="Manga style (right-to-left reading and splitting)") + mainOptions.add_option("-q", "--hq", action="store_true", dest="hq", default=False, + help="Try to increase the quality of magnification") mainOptions.add_option("-2", "--two-panel", action="store_true", dest="autoscale", default=False, help="Display two not four panels in Panel View mode") mainOptions.add_option("-w", "--webtoon", action="store_true", dest="webtoon", default=False, @@ -960,16 +969,20 @@ def checkOptions(): # Older Kindle models don't support Panel View. if options.profile == 'K1' or options.profile == 'K2' or options.profile == 'KDX': options.panelview = False + options.hq = False # Webtoon mode mandatory options if options.webtoon: options.panelview = False options.righttoleft = False options.upscale = True + options.hq = False # Disable all Kindle features for other e-readers if options.profile == 'OTHER': options.panelview = False + options.hq = False if 'Ko' in options.profile: options.panelview = False + options.hq = False # CBZ files on Kindle DX/DXG support higher resolution if options.profile == 'KDX' and options.format == 'CBZ': options.customheight = 1200 @@ -1185,9 +1198,11 @@ def makeMOBI(work, qtGUI=None): threadNumber = 1 elif 2 < availableMemory <= 4: threadNumber = 2 - else: + elif 4 < availableMemory <= 8: threadNumber = 4 - makeMOBIWorkerPool = Pool(threadNumber) + else: + threadNumber = None + makeMOBIWorkerPool = Pool(threadNumber, maxtasksperchild=10) for i in work: makeMOBIWorkerPool.apply_async(func=makeMOBIWorker, args=(i, ), callback=makeMOBIWorkerTick) makeMOBIWorkerPool.close() diff --git a/kindlecomicconverter/comic2panel.py b/kindlecomicconverter/comic2panel.py index e173575..2bb92b8 100644 --- a/kindlecomicconverter/comic2panel.py +++ b/kindlecomicconverter/comic2panel.py @@ -23,7 +23,7 @@ import sys from shutil import rmtree, copytree, move from optparse import OptionParser, OptionGroup from multiprocessing import Pool -from PIL import Image, ImageStat, ImageOps +from PIL import Image, ImageChops, ImageOps, ImageDraw from .shared import getImageFileName, walkLevel, walkSort, sanitizeTrace try: from PyQt5 import QtCore @@ -67,8 +67,7 @@ def mergeDirectory(work): result = Image.new('RGB', (targetWidth, targetHeight)) y = 0 for i in imagesValid: - img = Image.open(i) - img = img.convert('RGB') + img = Image.open(i).convert('RGB') if img.size[0] < targetWidth: img = ImageOps.fit(img, (targetWidth, img.size[1]), method=Image.BICUBIC, centering=(0.5, 0.5)) result.paste(img, (0, y)) @@ -80,30 +79,8 @@ def mergeDirectory(work): return str(sys.exc_info()[1]), sanitizeTrace(sys.exc_info()[2]) -def sanitizePanelSize(panel, opt): - newPanels = [] - if panel[2] > 6 * opt.height: - diff = int(panel[2] / 8) - newPanels.append([panel[0], panel[1] - diff * 7, diff]) - newPanels.append([panel[1] - diff * 7, panel[1] - diff * 6, diff]) - newPanels.append([panel[1] - diff * 6, panel[1] - diff * 5, diff]) - newPanels.append([panel[1] - diff * 5, panel[1] - diff * 4, diff]) - newPanels.append([panel[1] - diff * 4, panel[1] - diff * 3, diff]) - newPanels.append([panel[1] - diff * 3, panel[1] - diff * 2, diff]) - newPanels.append([panel[1] - diff * 2, panel[1] - diff, diff]) - newPanels.append([panel[1] - diff, panel[1], diff]) - elif panel[2] > 3 * opt.height: - diff = int(panel[2] / 4) - newPanels.append([panel[0], panel[1] - diff * 3, diff]) - newPanels.append([panel[1] - diff * 3, panel[1] - diff * 2, diff]) - newPanels.append([panel[1] - diff * 2, panel[1] - diff, diff]) - newPanels.append([panel[1] - diff, panel[1], diff]) - elif panel[2] > 1.5 * opt.height: - newPanels.append([panel[0], panel[1] - int(panel[2] / 2), int(panel[2] / 2)]) - newPanels.append([panel[1] - int(panel[2] / 2), panel[1], int(panel[2] / 2)]) - else: - newPanels = [panel] - return newPanels +def detectSolid(img): + return not ImageChops.invert(img).getbbox() or not img.getbbox() def splitImageTick(output): @@ -121,56 +98,60 @@ def splitImage(work): path = work[0] name = work[1] opt = work[2] - # Hardcoded options - threshold = 1.0 - delta = 15 - fileExpanded = os.path.splitext(name) filePath = os.path.join(path, name) - image = Image.open(filePath) - image = image.convert('RGB') - widthImg, heightImg = image.size + imgOrg = Image.open(filePath).convert('RGB') + imgProcess = Image.open(filePath).convert('1') + widthImg, heightImg = imgOrg.size if heightImg > opt.height: if opt.debug: - from PIL import ImageDraw - debugImage = Image.open(filePath) - draw = ImageDraw.Draw(debugImage) + drawImg = Image.open(filePath).convert(mode='RGBA') + draw = ImageDraw.Draw(drawImg) # Find panels - y1 = 0 - y2 = 15 + yWork = 0 + panelDetected = False 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) + while yWork < heightImg: + tmpImg = imgProcess.crop([0, yWork, widthImg, yWork + 4]) + solid = detectSolid(tmpImg) + if not solid and not panelDetected: + panelDetected = True + panelY1 = yWork - 2 + if solid and panelDetected: + panelDetected = False + panelY2 = yWork + 6 + panels.append((panelY1, panelY2, panelY2 - panelY1)) + yWork += 5 + + # Split too big panels + panelsProcessed = [] + for panel in panels: + if panel[2] <= opt.height * 1.5: + panelsProcessed.append(panel) + elif panel[2] < opt.height * 2: + diff = panel[2] - opt.height + panelsProcessed.append((panel[0], panel[1] - diff, opt.height)) + panelsProcessed.append((panel[1] - opt.height, panel[1], opt.height)) + else: + parts = round(panel[2] / opt.height) + diff = panel[2] // parts + for x in range(0, parts): + panelsProcessed.append((panel[0] + (x * diff), panel[1] - ((parts - x - 1) * diff), diff)) + if opt.debug: + for panel in panelsProcessed: + # noinspection PyUnboundLocalVariable + draw.rectangle([(0, panel[0]), (widthImg, panel[1])], (0, 255, 0, 128), (0, 0, 255, 255)) # noinspection PyUnboundLocalVariable - debugImage.save(os.path.join(path, fileExpanded[0] + '-debug.png'), 'PNG') + debugImage = Image.alpha_composite(imgOrg.convert(mode='RGBA'), drawImg) + debugImage.save(os.path.join(path, os.path.splitext(name)[0] + '-debug.png'), 'PNG') # Create virtual pages pages = [] currentPage = [] pageLeft = opt.height panelNumber = 0 - for panel in panels: + for panel in panelsProcessed: if pageLeft - panel[2] > 0: pageLeft -= panel[2] currentPage.append(panelNumber) @@ -190,14 +171,14 @@ def splitImage(work): pageHeight = 0 targetHeight = 0 for panel in page: - pageHeight += panels[panel][2] - if pageHeight > delta: + pageHeight += panelsProcessed[panel][2] + if pageHeight > 15: newPage = Image.new('RGB', (widthImg, pageHeight)) for panel in page: - panelImg = image.crop([0, panels[panel][0], widthImg, panels[panel][1]]) + panelImg = imgOrg.crop([0, panelsProcessed[panel][0], widthImg, panelsProcessed[panel][1]]) newPage.paste(panelImg, (0, targetHeight)) - targetHeight += panels[panel][2] - newPage.save(os.path.join(path, fileExpanded[0] + '-' + str(pageNumber) + '.png'), 'PNG') + targetHeight += panelsProcessed[panel][2] + newPage.save(os.path.join(path, os.path.splitext(name)[0] + '-' + str(pageNumber) + '.png'), 'PNG') pageNumber += 1 os.remove(filePath) except Exception: @@ -238,13 +219,13 @@ def main(argv=None, qtGUI=None): work = [] pagenumber = 1 splitWorkerOutput = [] - splitWorkerPool = Pool() + splitWorkerPool = Pool(maxtasksperchild=10) if options.merge: print("Merging images...") directoryNumer = 1 mergeWork = [] mergeWorkerOutput = [] - mergeWorkerPool = Pool() + mergeWorkerPool = Pool(maxtasksperchild=10) mergeWork.append([options.targetDir]) for root, dirs, files in os.walk(options.targetDir, False): dirs, files = walkSort(dirs, files) @@ -263,7 +244,8 @@ def main(argv=None, qtGUI=None): raise UserWarning("Conversion interrupted.") if len(mergeWorkerOutput) > 0: rmtree(options.targetDir, True) - raise RuntimeError("One of workers crashed. Cause: " + mergeWorkerOutput[0][0], mergeWorkerOutput[0][1]) + raise RuntimeError("One of workers crashed. Cause: " + mergeWorkerOutput[0][0], + mergeWorkerOutput[0][1]) print("Splitting images...") for root, _, files in os.walk(options.targetDir, False): for name in files: @@ -286,7 +268,8 @@ def main(argv=None, qtGUI=None): raise UserWarning("Conversion interrupted.") if len(splitWorkerOutput) > 0: rmtree(options.targetDir, True) - raise RuntimeError("One of workers crashed. Cause: " + splitWorkerOutput[0][0], splitWorkerOutput[0][1]) + raise RuntimeError("One of workers crashed. Cause: " + splitWorkerOutput[0][0], + splitWorkerOutput[0][1]) if options.inPlace: rmtree(options.sourceDir) move(options.targetDir, options.sourceDir) diff --git a/kindlecomicconverter/image.py b/kindlecomicconverter/image.py index 5035a9e..a380648 100755 --- a/kindlecomicconverter/image.py +++ b/kindlecomicconverter/image.py @@ -120,7 +120,7 @@ class ComicPageParser: width, height = self.image.size dstwidth, dstheight = self.size if (width > height) != (dstwidth > dstheight) and width <= dstheight and height <= dstwidth \ - and not self.opt.webtoon: + and not self.opt.webtoon and self.opt.splitter == 1: self.payload.append(['R', self.source, self.image.rotate(90, Image.BICUBIC, True), self.color, self.fill]) elif (width > height) != (dstwidth > dstheight) and not self.opt.webtoon: if self.opt.splitter != 1: @@ -209,6 +209,8 @@ class ComicPage: def __init__(self, options, mode, path, image, color, fill): self.opt = options _, self.size, self.palette, self.gamma = self.opt.profileData + if self.opt.hq: + self.size = (int(self.size[0] * 1.5), int(self.size[1] * 1.5)) self.image = image self.color = color self.fill = fill diff --git a/kindlecomicconverter/shared.py b/kindlecomicconverter/shared.py index 00ae3b9..89e0b19 100644 --- a/kindlecomicconverter/shared.py +++ b/kindlecomicconverter/shared.py @@ -17,11 +17,9 @@ # import os -from sys import version_info from hashlib import md5 from html.parser import HTMLParser from distutils.version import StrictVersion -from time import sleep from shutil import rmtree, copy from tempfile import mkdtemp from zipfile import ZipFile, ZIP_DEFLATED diff --git a/kindlecomicconverter/startup.py b/kindlecomicconverter/startup.py index 4c47a17..aa78a0a 100644 --- a/kindlecomicconverter/startup.py +++ b/kindlecomicconverter/startup.py @@ -23,6 +23,7 @@ import sys from . import __version__ from .shared import dependencyCheck + def start(): dependencyCheck(3) from . import KCC_gui @@ -40,14 +41,16 @@ def start(): KCCUI.handleMessage(sys.argv[1]) sys.exit(KCCAplication.exec_()) + def startC2E(): dependencyCheck(2) from .comic2ebook import main print('comic2ebook v' + __version__ + ' - Written by Ciro Mattia Gonano and Pawel Jastrzebski.') sys.exit(main(sys.argv[1:])) + def startC2P(): dependencyCheck(1) from .comic2panel import main print('comic2panel v' + __version__ + ' - Written by Ciro Mattia Gonano and Pawel Jastrzebski.') - sys.exit(main(sys.argv[1:])) \ No newline at end of file + sys.exit(main(sys.argv[1:])) diff --git a/other/osx/Info.plist b/other/osx/Info.plist index dce11bb..0b4d894 100644 --- a/other/osx/Info.plist +++ b/other/osx/Info.plist @@ -30,7 +30,7 @@ <key>CFBundleExecutable</key> <string>MacOS/Kindle Comic Converter</string> <key>CFBundleGetInfoString</key> - <string>KindleComicConverter 5.3.1, written 2012-2017 by Ciro Mattia Gonano and Pawel Jastrzebski</string> + <string>KindleComicConverter 5.4.0, written 2012-2017 by Ciro Mattia Gonano and Pawel Jastrzebski</string> <key>CFBundleIconFile</key> <string>comic2ebook.icns</string> <key>CFBundleIdentifier</key> @@ -42,11 +42,11 @@ <key>CFBundlePackageType</key> <string>APPL</string> <key>CFBundleShortVersionString</key> - <string>5.3.1</string> + <string>5.4.0</string> <key>CFBundleSignature</key> <string>????</string> <key>CFBundleVersion</key> - <string>5.3.1</string> + <string>5.4.0</string> <key>LSEnvironment</key> <dict> <key>PATH</key> diff --git a/setup.py b/setup.py index 7e330fe..278c4a7 100755 --- a/setup.py +++ b/setup.py @@ -2,10 +2,10 @@ """ pip/pyinstaller build script for KCC. -Usage (Windows): - py -3 setup.py build_binary +Install as Python package: + python3 setup.py install -Usage (Linux/OS X): +Create EXE/APP/DEB: python3 setup.py build_binary """ @@ -14,32 +14,22 @@ import sys import shutil import setuptools import distutils.cmd -from distutils.command.build import build from kindlecomicconverter import __version__ NAME = 'KindleComicConverter' MAIN = 'kcc.py' VERSION = __version__ + class BuildBinaryCommand(distutils.cmd.Command): description = 'build binary release' - user_options = [ - ('pyz', None, 'build PYZ package'), - ] - - def initialize_options(self): - # noinspection PyAttributeOutsideInit - self.pyz = False - - def finalize_options(self): - pass def run(self): if sys.platform == 'darwin': if os.path.isfile('Kindle Comic Converter.spec'): os.system('pyinstaller "Kindle Comic Converter.spec"') else: - os.system('pyinstaller -y -F -i icons/comic2ebook.icns -n "Kindle Comic Converter" -w -s --noupx kcc.py') + os.system('pyinstaller -y -F -i icons/comic2ebook.icns -n "Kindle Comic Converter" -w -s kcc.py') shutil.copy('other/osx/7za', 'dist/Kindle Comic Converter.app/Contents/Resources') shutil.copy('other/osx/unrar', 'dist/Kindle Comic Converter.app/Contents/Resources') shutil.copy('other/osx/Info.plist', 'dist/Kindle Comic Converter.app/Contents') @@ -92,6 +82,6 @@ setuptools.setup( 'python-slugify>=1.2.1', 'raven>=6.0.0', ], - classifiers = [], + classifiers=[], zip_safe=False, ) |