1
0
mirror of https://github.com/ciromattia/kcc synced 2025-12-13 01:36:27 +00:00

Overhauled webtoon splitter

This commit is contained in:
Paweł Jastrzębski
2017-03-19 07:58:48 +01:00
parent 1895aa127d
commit 02dab3c6ee

View File

@@ -23,7 +23,7 @@ import sys
from shutil import rmtree, copytree, move from shutil import rmtree, copytree, move
from optparse import OptionParser, OptionGroup from optparse import OptionParser, OptionGroup
from multiprocessing import Pool from multiprocessing import Pool
from PIL import Image, ImageStat, ImageOps from PIL import Image, ImageChops, ImageOps, ImageDraw
from .shared import getImageFileName, walkLevel, walkSort, sanitizeTrace from .shared import getImageFileName, walkLevel, walkSort, sanitizeTrace
try: try:
from PyQt5 import QtCore from PyQt5 import QtCore
@@ -67,8 +67,7 @@ def mergeDirectory(work):
result = Image.new('RGB', (targetWidth, targetHeight)) result = Image.new('RGB', (targetWidth, targetHeight))
y = 0 y = 0
for i in imagesValid: for i in imagesValid:
img = Image.open(i) img = Image.open(i).convert('RGB')
img = img.convert('RGB')
if img.size[0] < targetWidth: if img.size[0] < targetWidth:
img = ImageOps.fit(img, (targetWidth, img.size[1]), method=Image.BICUBIC, centering=(0.5, 0.5)) img = ImageOps.fit(img, (targetWidth, img.size[1]), method=Image.BICUBIC, centering=(0.5, 0.5))
result.paste(img, (0, y)) result.paste(img, (0, y))
@@ -80,30 +79,8 @@ def mergeDirectory(work):
return str(sys.exc_info()[1]), sanitizeTrace(sys.exc_info()[2]) return str(sys.exc_info()[1]), sanitizeTrace(sys.exc_info()[2])
def sanitizePanelSize(panel, opt): def detectSolid(img):
newPanels = [] return not ImageChops.invert(img).getbbox() or not img.getbbox()
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 splitImageTick(output): def splitImageTick(output):
@@ -121,56 +98,75 @@ def splitImage(work):
path = work[0] path = work[0]
name = work[1] name = work[1]
opt = work[2] opt = work[2]
# Hardcoded options
threshold = 1.0
delta = 15
fileExpanded = os.path.splitext(name)
filePath = os.path.join(path, name) filePath = os.path.join(path, name)
image = Image.open(filePath) imgOrg = Image.open(filePath).convert('RGB')
image = image.convert('RGB') imgProcess = Image.open(filePath).convert('L')
widthImg, heightImg = image.size widthImg, heightImg = imgOrg.size
if heightImg > opt.height: if heightImg > opt.height:
if opt.debug: if opt.debug:
from PIL import ImageDraw drawImg = Image.open(filePath).convert(mode='RGBA')
debugImage = Image.open(filePath) draw = ImageDraw.Draw(drawImg)
draw = ImageDraw.Draw(debugImage)
# Find panels # Find panels
y1 = 0 yWork = 0
y2 = 15 panelDetected = False
panels = [] panels = []
while y2 < heightImg: while yWork < heightImg:
while ImageStat.Stat(image.crop([0, y1, widthImg, y2])).var[0] < threshold and y2 < heightImg: tmpImg = imgProcess.crop([0, yWork, widthImg, yWork + 4])
y2 += delta solid = detectSolid(tmpImg)
y2 -= delta if not solid and not panelDetected:
y1Temp = y2 panelDetected = True
y1 = y2 + delta panelY1 = yWork - 2
y2 = y1 + delta if solid and panelDetected:
while ImageStat.Stat(image.crop([0, y1, widthImg, y2])).var[0] >= threshold and y2 < heightImg: panelDetected = False
y1 += delta panelY2 = yWork + 6
y2 += delta panels.append((panelY1, panelY2, panelY2 - panelY1))
if y1 + delta >= heightImg: yWork += 5
y1 = heightImg - 1
y2Temp = y1 # Merge nearby panels
if opt.debug: panelsMerged = []
draw.line([(0, y1Temp), (widthImg, y1Temp)], fill=(0, 255, 0)) previousPanel = False
draw.line([(0, y2Temp), (widthImg, y2Temp)], fill=(255, 0, 0)) for panel in panels:
panelHeight = y2Temp - y1Temp if not previousPanel:
if panelHeight > delta: previousPanel = panel
# Panels that can't be cut nicely will be forcefully splitted continue
panelsCleaned = sanitizePanelSize([y1Temp, y2Temp, panelHeight], opt) if panel[0] - previousPanel[1] <= 15:
for panel in panelsCleaned: previousPanel = (previousPanel[0], panel[1], panel[1] - previousPanel[0])
panels.append(panel) 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: 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 # 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 # Create virtual pages
pages = [] pages = []
currentPage = [] currentPage = []
pageLeft = opt.height pageLeft = opt.height
panelNumber = 0 panelNumber = 0
for panel in panels: for panel in panelsProcessed:
if pageLeft - panel[2] > 0: if pageLeft - panel[2] > 0:
pageLeft -= panel[2] pageLeft -= panel[2]
currentPage.append(panelNumber) currentPage.append(panelNumber)
@@ -190,14 +186,14 @@ def splitImage(work):
pageHeight = 0 pageHeight = 0
targetHeight = 0 targetHeight = 0
for panel in page: for panel in page:
pageHeight += panels[panel][2] pageHeight += panelsProcessed[panel][2]
if pageHeight > delta: if pageHeight > 15:
newPage = Image.new('RGB', (widthImg, pageHeight)) newPage = Image.new('RGB', (widthImg, pageHeight))
for panel in page: 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)) newPage.paste(panelImg, (0, targetHeight))
targetHeight += panels[panel][2] targetHeight += panelsProcessed[panel][2]
newPage.save(os.path.join(path, fileExpanded[0] + '-' + str(pageNumber) + '.png'), 'PNG') newPage.save(os.path.join(path, os.path.splitext(name)[0] + '-' + str(pageNumber) + '.png'), 'PNG')
pageNumber += 1 pageNumber += 1
os.remove(filePath) os.remove(filePath)
except Exception: except Exception: