diff options
author | Paweł Jastrzębski <pawelj@iosphe.re> | 2017-03-19 07:58:48 +0100 |
---|---|---|
committer | Paweł Jastrzębski <pawelj@iosphe.re> | 2017-03-22 07:56:23 +0100 |
commit | 02dab3c6eeb19975e5966cb5d90e11b10f91261a (patch) | |
tree | 4086739d96a679776bd5469e556925d18c244407 /kindlecomicconverter/comic2panel.py | |
parent | Decrease memory usage (diff) | |
download | kcc-02dab3c6eeb19975e5966cb5d90e11b10f91261a.tar.gz kcc-02dab3c6eeb19975e5966cb5d90e11b10f91261a.tar.bz2 kcc-02dab3c6eeb19975e5966cb5d90e11b10f91261a.zip |
Overhauled webtoon splitter
Diffstat (limited to 'kindlecomicconverter/comic2panel.py')
-rw-r--r-- | kindlecomicconverter/comic2panel.py | 132 |
1 files changed, 64 insertions, 68 deletions
diff --git a/kindlecomicconverter/comic2panel.py b/kindlecomicconverter/comic2panel.py index 8618cda..f4fb6c6 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,75 @@ 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('L') + 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 + + # Merge nearby panels + panelsMerged = [] + previousPanel = False + for panel in panels: + if not previousPanel: + previousPanel = panel + continue + if panel[0] - previousPanel[1] <= 15: + previousPanel = (previousPanel[0], panel[1], panel[1] - previousPanel[0]) + else: + panelsMerged.append(previousPanel) + previousPanel = panel + if panels: + panelsMerged.append(panels[-1]) + + # Split too big panels + panelsProcessed = [] + for panel in panelsMerged: + 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 +186,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: |