1
0
mirror of https://github.com/ciromattia/kcc synced 2025-12-15 10:46:40 +00:00

OptionParser to ArgumentParser (#517)

This commit is contained in:
darodi
2023-05-14 16:31:45 +00:00
committed by GitHub
parent d16628dc59
commit 0bbe9348a2
8 changed files with 244 additions and 247 deletions

124
README.md
View File

@@ -136,89 +136,81 @@ sudo apt-get install python3 p7zip-full python3-pil python3-psutil python3-slugi
### Standalone `kcc-c2e.py` usage: ### Standalone `kcc-c2e.py` usage:
``` ```
Usage: kcc-c2e [options] comic_file|comic_folder usage: kcc-c2e [options] [input]
Options: MANDATORY:
MAIN: input Full path to comic folder or file(s) to be processed.
-p PROFILE, --profile=PROFILE
Device profile (Available options: K1, K2, K34, K578,
KDX, KPW, KPW5, KV, KO, K11, KS, KoMT, KoG, KoGHD,
KoA, KoAHD, KoAH2O, KoAO, KoN, KoC, KoL, KoF, KoS,
KoE) [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
--targetsize=TARGETSIZE
the maximal size of output file in MB. [Default=100MB
for webtoon and 400MB for others]
OUTPUT SETTINGS: MAIN:
-o OUTPUT, --output=OUTPUT -p PROFILE, --profile PROFILE
Output generated file to specified directory or file Device profile (Available options: K1, K2, K34, K578, KDX, KPW, KPW5, KV, KO, K11, KS, KoMT, KoG, KoGHD, KoA, KoAHD, KoAH2O, KoAO, KoN, KoC, KoL, KoF, KoS, KoE) [Default=KV]
-t TITLE, --title=TITLE -m, --manga-style Manga style (right-to-left reading and splitting)
Comic title [Default=filename or directory name] -q, --hq Try to increase the quality of magnification
-f FORMAT, --format=FORMAT -2, --two-panel Display two not four panels in Panel View mode
Output format (Available options: Auto, MOBI, EPUB, -w, --webtoon Webtoon processing mode
CBZ, KFX, MOBI+EPUB) [Default=Auto] --ts TARGETSIZE, --targetsize TARGETSIZE
-b BATCHSPLIT, --batchsplit=BATCHSPLIT the maximal size of output file in MB. [Default=100MB for webtoon and 400MB for others]
Split output into multiple files. 0: Don't split 1:
Automatic mode 2: Consider every subdirectory as
separate volume [Default=0]
PROCESSING: PROCESSING:
-n, --noprocessing Do not modify image and ignore any profil or -n, --noprocessing Do not modify image and ignore any profil or processing option
processing option -u, --upscale Resize images smaller than device's resolution
-u, --upscale Resize images smaller than device's resolution -s, --stretch Stretch images to device's resolution
-s, --stretch Stretch images to device's resolution -r SPLITTER, --splitter SPLITTER
-r SPLITTER, --splitter=SPLITTER Double page parsing mode. 0: Split 1: Rotate 2: Both [Default=0]
Double page parsing mode. 0: Split 1: Rotate 2: Both -g GAMMA, --gamma GAMMA
[Default=0] Apply gamma correction to linearize the image [Default=Auto]
-g GAMMA, --gamma=GAMMA -c CROPPING, --cropping CROPPING
Apply gamma correction to linearize the image Set cropping mode. 0: Disabled 1: Margins 2: Margins + page numbers [Default=2]
[Default=Auto] --cp CROPPINGP, --croppingpower CROPPINGP
-c CROPPING, --cropping=CROPPING
Set cropping mode. 0: Disabled 1: Margins 2: Margins +
page numbers [Default=2]
--cp=CROPPINGP, --croppingpower=CROPPINGP
Set cropping power [Default=1.0] Set cropping power [Default=1.0]
--cm=CROPPINGM, --croppingminimum=CROPPINGM --cm CROPPINGM, --croppingminimum CROPPINGM
Set cropping minimum area ratio [Default=0.0] Set cropping minimum area ratio [Default=0.0]
--blackborders Disable autodetection and force black borders --blackborders Disable autodetection and force black borders
--whiteborders Disable autodetection and force white borders --whiteborders Disable autodetection and force white borders
--forcecolor Don't convert images to grayscale --forcecolor Don't convert images to grayscale
--forcepng Create PNG files instead JPEG --forcepng Create PNG files instead JPEG
--mozjpeg Create JPEG files using mozJpeg --mozjpeg Create JPEG files using mozJpeg
--maximizestrips Turn 1x4 strips to 2x2 strips --maximizestrips Turn 1x4 strips to 2x2 strips
-d, --delete Delete source file(s) or a directory. It's not -d, --delete Delete source file(s) or a directory. It's not recoverable.
recoverable.
CUSTOM PROFILE: OUTPUT SETTINGS:
--customwidth=CUSTOMWIDTH -o OUTPUT, --output OUTPUT
Output generated file to specified directory or file
-t TITLE, --title TITLE
Comic title [Default=filename or directory name]
-f FORMAT, --format FORMAT
Output format (Available options: Auto, MOBI, EPUB, CBZ, KFX, MOBI+EPUB) [Default=Auto]
-b BATCHSPLIT, --batchsplit BATCHSPLIT
Split output into multiple files. 0: Don't split 1: Automatic mode 2: Consider every subdirectory as separate volume [Default=0]
CUSTOM PROFILE:
--customwidth CUSTOMWIDTH
Replace screen width provided by device profile Replace screen width provided by device profile
--customheight=CUSTOMHEIGHT --customheight CUSTOMHEIGHT
Replace screen height provided by device profile Replace screen height provided by device profile
OTHER: OTHER:
-h, --help Show this help message and exit -h, --help Show this help message and exit
``` ```
### Standalone `kcc-c2p.py` usage: ### Standalone `kcc-c2p.py` usage:
``` ```
Usage: kcc-c2p [options] comic_folder usage: kcc-c2p [options] [input]
Options: MANDATORY:
MANDATORY: input Full path to comic folder(s) to be processed. Separate multiple inputs with spaces.
-y HEIGHT, --height=HEIGHT
MAIN:
-y HEIGHT, --height HEIGHT
Height of the target device screen Height of the target device screen
-i, --in-place Overwrite source directory -i, --in-place Overwrite source directory
-m, --merge Combine every directory into a single image before -m, --merge Combine every directory into a single image before splitting
splitting
OTHER: OTHER:
-d, --debug Create debug file for every split image -d, --debug Create debug file for every split image
-h, --help Show this help message and exit -h, --help Show this help message and exit
``` ```
## CREDITS ## CREDITS

View File

@@ -19,8 +19,9 @@
# PERFORMANCE OF THIS SOFTWARE. # PERFORMANCE OF THIS SOFTWARE.
import sys import sys
if sys.version_info[0] != 3:
print('ERROR: This is Python 3 script!') if sys.version_info < (3, 8, 0):
print('ERROR: This is a Python 3.8+ script!')
exit(1) exit(1)
from multiprocessing import freeze_support, set_start_method from multiprocessing import freeze_support, set_start_method

View File

@@ -19,8 +19,9 @@
# PERFORMANCE OF THIS SOFTWARE. # PERFORMANCE OF THIS SOFTWARE.
import sys import sys
if sys.version_info[0] != 3:
print('ERROR: This is Python 3 script!') if sys.version_info < (3, 8, 0):
print('ERROR: This is a Python 3.8+ script!')
exit(1) exit(1)
from multiprocessing import freeze_support, set_start_method from multiprocessing import freeze_support, set_start_method

5
kcc.py
View File

@@ -19,8 +19,9 @@
# PERFORMANCE OF THIS SOFTWARE. # PERFORMANCE OF THIS SOFTWARE.
import sys import sys
if sys.version_info[0] != 3:
print('ERROR: This is Python 3 script!') if sys.version_info < (3, 8, 0):
print('ERROR: This is a Python 3.8+ script!')
exit(1) exit(1)
# OS specific workarounds # OS specific workarounds

View File

@@ -219,7 +219,7 @@ class WorkerThread(QtCore.QThread):
MW.modeConvert.emit(0) MW.modeConvert.emit(0)
parser = comic2ebook.makeParser() parser = comic2ebook.makeParser()
options, _ = parser.parse_args() options = parser.parse_args()
argv = '' argv = ''
currentJobs = [] currentJobs = []

View File

@@ -20,6 +20,7 @@
import os import os
import sys import sys
from argparse import ArgumentParser
from time import strftime, gmtime from time import strftime, gmtime
from copy import copy from copy import copy
from glob import glob, escape from glob import glob, escape
@@ -28,10 +29,9 @@ from stat import S_IWRITE, S_IREAD, S_IEXEC
from zipfile import ZipFile, ZIP_STORED, ZIP_DEFLATED from zipfile import ZipFile, ZIP_STORED, ZIP_DEFLATED
from tempfile import mkdtemp, gettempdir, TemporaryFile from tempfile import mkdtemp, gettempdir, TemporaryFile
from shutil import move, copytree, rmtree, copyfile from shutil import move, copytree, rmtree, copyfile
from optparse import OptionParser, OptionGroup
from multiprocessing import Pool from multiprocessing import Pool
from uuid import uuid4 from uuid import uuid4
from slugify import slugify as slugifyExt from slugify import slugify as slugify_ext
from PIL import Image from PIL import Image
from subprocess import STDOUT, PIPE from subprocess import STDOUT, PIPE
from psutil import Popen, virtual_memory, disk_usage from psutil import Popen, virtual_memory, disk_usage
@@ -54,23 +54,23 @@ from . import __version__
def main(argv=None): def main(argv=None):
global options global options
parser = makeParser() parser = makeParser()
optionstemplate, args = parser.parse_args(argv) args = parser.parse_args(argv)
if len(args) == 0: options = copy(args)
if not argv or options.input == []:
parser.print_help() parser.print_help()
return 0 return 0
if sys.platform.startswith('win'): if sys.platform.startswith('win'):
sources = set([source for arg in args for source in glob(escape(arg))]) sources = set([source for option in options.input for source in glob(escape(option))])
else: else:
sources = set(args) sources = set(options.input)
if len(sources) == 0: if len(sources) == 0:
print('No matching files found.') print('No matching files found.')
return 1 return 1
for source in sources: for source in sources:
source = source.rstrip('\\').rstrip('/') source = source.rstrip('\\').rstrip('/')
options = copy(optionstemplate) options = copy(args)
options = checkOptions(options) options = checkOptions(options)
if len(sources) > 1: print('Working on ' + source + '...')
print('Working on ' + source + '...')
makeBook(source) makeBook(source)
return 0 return 0
@@ -546,7 +546,7 @@ def imgDirectoryProcessing(path):
GUI.progressBarTick.emit(str(pagenumber)) GUI.progressBarTick.emit(str(pagenumber))
if len(work) > 0: if len(work) > 0:
for i in work: for i in work:
workerPool.apply_async(func=imgFileProcessing, args=(i, ), callback=imgFileProcessingTick) workerPool.apply_async(func=imgFileProcessing, args=(i,), callback=imgFileProcessingTick)
workerPool.close() workerPool.close()
workerPool.join() workerPool.join()
if GUI and not GUI.conversionAlive: if GUI and not GUI.conversionAlive:
@@ -910,9 +910,9 @@ def createNewTome():
def slugify(value, isdir): def slugify(value, isdir):
if isdir: if isdir:
value = slugifyExt(value, regex_pattern=r'[^-a-z0-9_\.]+').strip('.') value = slugify_ext(value, regex_pattern=r'[^-a-z0-9_\.]+').strip('.')
else: else:
value = slugifyExt(value).strip('.') value = slugify_ext(value).strip('.')
value = sub(r'0*([0-9]{4,})', r'\1', sub(r'([0-9]+)', r'0000\1', value, count=2)) value = sub(r'0*([0-9]{4,})', r'\1', sub(r'([0-9]+)', r'0000\1', value, count=2))
return value return value
@@ -933,85 +933,84 @@ def makeZIP(zipfilename, basedir, isepub=False):
def makeParser(): def makeParser():
psr = OptionParser(usage="Usage: kcc-c2e [options] comic_file|comic_folder", add_help_option=False) psr = ArgumentParser(prog="kcc-c2e", usage="kcc-c2e [options] [input]", add_help=False)
mainOptions = OptionGroup(psr, "MAIN") mandatory_options = psr.add_argument_group("MANDATORY")
processingOptions = OptionGroup(psr, "PROCESSING") main_options = psr.add_argument_group("MAIN")
outputOptions = OptionGroup(psr, "OUTPUT SETTINGS") processing_options = psr.add_argument_group("PROCESSING")
customProfileOptions = OptionGroup(psr, "CUSTOM PROFILE") output_options = psr.add_argument_group("OUTPUT SETTINGS")
otherOptions = OptionGroup(psr, "OTHER") custom_profile_options = psr.add_argument_group("CUSTOM PROFILE")
other_options = psr.add_argument_group("OTHER")
mainOptions.add_option("-p", "--profile", action="store", dest="profile", default="KV", mandatory_options.add_argument("input", action="extend", nargs="*", default=None,
help="Device profile (Available options: K1, K2, K34, K578, KDX, KPW, KPW5, KV, KO, " help="Full path to comic folder or file(s) to be processed.")
"K11, KS, KoMT, KoG, KoGHD, KoA, KoAHD, KoAH2O, KoAO, KoN, KoC, KoL, KoF, KoS, KoE)"
" [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,
help="Webtoon processing mode"),
mainOptions.add_option("--targetsize", type="int", dest="targetsize", default=None,
help="the maximal size of output file in MB."
" [Default=100MB for webtoon and 400MB for others]")
outputOptions.add_option("-o", "--output", action="store", dest="output", default=None, main_options.add_argument("-p", "--profile", action="store", dest="profile", default="KV",
help="Output generated file to specified directory or file") help="Device profile (Available options: K1, K2, K34, K578, KDX, KPW, KPW5, KV, KO, "
outputOptions.add_option("-t", "--title", action="store", dest="title", default="defaulttitle", "K11, KS, KoMT, KoG, KoGHD, KoA, KoAHD, KoAH2O, KoAO, KoN, KoC, KoL, KoF, KoS, KoE)"
help="Comic title [Default=filename or directory name]") " [Default=KV]")
outputOptions.add_option("-f", "--format", action="store", dest="format", default="Auto", main_options.add_argument("-m", "--manga-style", action="store_true", dest="righttoleft", default=False,
help="Output format (Available options: Auto, MOBI, EPUB, CBZ, KFX, MOBI+EPUB) " help="Manga style (right-to-left reading and splitting)")
"[Default=Auto]") main_options.add_argument("-q", "--hq", action="store_true", dest="hq", default=False,
outputOptions.add_option("-b", "--batchsplit", type="int", dest="batchsplit", default="0", help="Try to increase the quality of magnification")
help="Split output into multiple files. 0: Don't split 1: Automatic mode " main_options.add_argument("-2", "--two-panel", action="store_true", dest="autoscale", default=False,
"2: Consider every subdirectory as separate volume [Default=0]") help="Display two not four panels in Panel View mode")
main_options.add_argument("-w", "--webtoon", action="store_true", dest="webtoon", default=False,
help="Webtoon processing mode"),
main_options.add_argument("--ts", "--targetsize", type=int, dest="targetsize", default=None,
help="the maximal size of output file in MB."
" [Default=100MB for webtoon and 400MB for others]")
processingOptions.add_option("-n", "--noprocessing", action="store_true", dest="noprocessing", default=False, output_options.add_argument("-o", "--output", action="store", dest="output", default=None,
help="Do not modify image and ignore any profil or processing option") help="Output generated file to specified directory or file")
processingOptions.add_option("-u", "--upscale", action="store_true", dest="upscale", default=False, output_options.add_argument("-t", "--title", action="store", dest="title", default="defaulttitle",
help="Resize images smaller than device's resolution") help="Comic title [Default=filename or directory name]")
processingOptions.add_option("-s", "--stretch", action="store_true", dest="stretch", default=False, output_options.add_argument("-f", "--format", action="store", dest="format", default="Auto",
help="Stretch images to device's resolution") help="Output format (Available options: Auto, MOBI, EPUB, CBZ, KFX, MOBI+EPUB) "
processingOptions.add_option("-r", "--splitter", type="int", dest="splitter", default="0", "[Default=Auto]")
help="Double page parsing mode. 0: Split 1: Rotate 2: Both [Default=0]") output_options.add_argument("-b", "--batchsplit", type=int, dest="batchsplit", default="0",
processingOptions.add_option("-g", "--gamma", type="float", dest="gamma", default="0.0", help="Split output into multiple files. 0: Don't split 1: Automatic mode "
help="Apply gamma correction to linearize the image [Default=Auto]") "2: Consider every subdirectory as separate volume [Default=0]")
processingOptions.add_option("-c", "--cropping", type="int", dest="cropping", default="2",
help="Set cropping mode. 0: Disabled 1: Margins 2: Margins + page numbers [Default=2]")
processingOptions.add_option("--cp", "--croppingpower", type="float", dest="croppingp", default="1.0",
help="Set cropping power [Default=1.0]")
processingOptions.add_option("--cm", "--croppingminimum", type="float", dest="croppingm", default="0.0",
help="Set cropping minimum area ratio [Default=0.0]")
processingOptions.add_option("--blackborders", action="store_true", dest="black_borders", default=False,
help="Disable autodetection and force black borders")
processingOptions.add_option("--whiteborders", action="store_true", dest="white_borders", default=False,
help="Disable autodetection and force white borders")
processingOptions.add_option("--forcecolor", action="store_true", dest="forcecolor", default=False,
help="Don't convert images to grayscale")
processingOptions.add_option("--forcepng", action="store_true", dest="forcepng", default=False,
help="Create PNG files instead JPEG")
processingOptions.add_option("--mozjpeg", action="store_true", dest="mozjpeg", default=False,
help="Create JPEG files using mozJpeg")
processingOptions.add_option("--maximizestrips", action="store_true", dest="maximizestrips", default=False,
help="Turn 1x4 strips to 2x2 strips")
processingOptions.add_option("-d", "--delete", action="store_true", dest="delete", default=False,
help="Delete source file(s) or a directory. It's not recoverable.")
customProfileOptions.add_option("--customwidth", type="int", dest="customwidth", default=0, processing_options.add_argument("-n", "--noprocessing", action="store_true", dest="noprocessing", default=False,
help="Replace screen width provided by device profile") help="Do not modify image and ignore any profil or processing option")
customProfileOptions.add_option("--customheight", type="int", dest="customheight", default=0, processing_options.add_argument("-u", "--upscale", action="store_true", dest="upscale", default=False,
help="Replace screen height provided by device profile") help="Resize images smaller than device's resolution")
processing_options.add_argument("-s", "--stretch", action="store_true", dest="stretch", default=False,
help="Stretch images to device's resolution")
processing_options.add_argument("-r", "--splitter", type=int, dest="splitter", default="0",
help="Double page parsing mode. 0: Split 1: Rotate 2: Both [Default=0]")
processing_options.add_argument("-g", "--gamma", type=float, dest="gamma", default="0.0",
help="Apply gamma correction to linearize the image [Default=Auto]")
processing_options.add_argument("-c", "--cropping", type=int, dest="cropping", default="2",
help="Set cropping mode. 0: Disabled 1: Margins 2: Margins + page numbers [Default=2]")
processing_options.add_argument("--cp", "--croppingpower", type=float, dest="croppingp", default="1.0",
help="Set cropping power [Default=1.0]")
processing_options.add_argument("--cm", "--croppingminimum", type=float, dest="croppingm", default="0.0",
help="Set cropping minimum area ratio [Default=0.0]")
processing_options.add_argument("--blackborders", action="store_true", dest="black_borders", default=False,
help="Disable autodetection and force black borders")
processing_options.add_argument("--whiteborders", action="store_true", dest="white_borders", default=False,
help="Disable autodetection and force white borders")
processing_options.add_argument("--forcecolor", action="store_true", dest="forcecolor", default=False,
help="Don't convert images to grayscale")
processing_options.add_argument("--forcepng", action="store_true", dest="forcepng", default=False,
help="Create PNG files instead JPEG")
processing_options.add_argument("--mozjpeg", action="store_true", dest="mozjpeg", default=False,
help="Create JPEG files using mozJpeg")
processing_options.add_argument("--maximizestrips", action="store_true", dest="maximizestrips", default=False,
help="Turn 1x4 strips to 2x2 strips")
processing_options.add_argument("-d", "--delete", action="store_true", dest="delete", default=False,
help="Delete source file(s) or a directory. It's not recoverable.")
otherOptions.add_option("-h", "--help", action="help", custom_profile_options.add_argument("--customwidth", type=int, dest="customwidth", default=0,
help="Show this help message and exit") help="Replace screen width provided by device profile")
custom_profile_options.add_argument("--customheight", type=int, dest="customheight", default=0,
help="Replace screen height provided by device profile")
other_options.add_argument("-h", "--help", action="help",
help="Show this help message and exit")
psr.add_option_group(mainOptions)
psr.add_option_group(outputOptions)
psr.add_option_group(processingOptions)
psr.add_option_group(customProfileOptions)
psr.add_option_group(otherOptions)
return psr return psr

View File

@@ -20,8 +20,8 @@
import os import os
import sys import sys
from argparse import ArgumentParser
from shutil import rmtree, copytree, move from shutil import rmtree, copytree, move
from optparse import OptionParser, OptionGroup
from multiprocessing import Pool from multiprocessing import Pool
from PIL import Image, ImageChops, ImageOps, ImageDraw from PIL import Image, ImageChops, ImageOps, ImageDraw
from .shared import getImageFileName, walkLevel, walkSort, sanitizeTrace from .shared import getImageFileName, walkLevel, walkSort, sanitizeTrace
@@ -102,7 +102,7 @@ def splitImage(work):
opt = work[2] opt = work[2]
filePath = os.path.join(path, name) filePath = os.path.join(path, name)
Image.warnings.simplefilter('error', Image.DecompressionBombWarning) Image.warnings.simplefilter('error', Image.DecompressionBombWarning)
Image.MAX_IMAGE_PIXELS = 1000000000 Image.MAX_IMAGE_PIXELS = 1000000000
imgOrg = Image.open(filePath).convert('RGB') imgOrg = Image.open(filePath).convert('RGB')
imgProcess = Image.open(filePath).convert('1') imgProcess = Image.open(filePath).convert('1')
widthImg, heightImg = imgOrg.size widthImg, heightImg = imgOrg.size
@@ -116,7 +116,7 @@ def splitImage(work):
panelDetected = False panelDetected = False
panels = [] panels = []
while yWork < heightImg: while yWork < heightImg:
tmpImg = imgProcess.crop([4, yWork, widthImg-4, yWork + 4]) tmpImg = imgProcess.crop((4, yWork, widthImg-4, yWork + 4))
solid = detectSolid(tmpImg) solid = detectSolid(tmpImg)
if not solid and not panelDetected: if not solid and not panelDetected:
panelDetected = True panelDetected = True
@@ -149,7 +149,7 @@ def splitImage(work):
if opt.debug: if opt.debug:
for panel in panelsProcessed: for panel in panelsProcessed:
draw.rectangle([(0, panel[0]), (widthImg, panel[1])], (0, 255, 0, 128), (0, 0, 255, 255)) draw.rectangle(((0, panel[0]), (widthImg, panel[1])), (0, 255, 0, 128), (0, 0, 255, 255))
debugImage = Image.alpha_composite(imgOrg.convert(mode='RGBA'), drawImg) debugImage = Image.alpha_composite(imgOrg.convert(mode='RGBA'), drawImg)
debugImage.save(os.path.join(path, os.path.splitext(name)[0] + '-debug.png'), 'PNG') debugImage.save(os.path.join(path, os.path.splitext(name)[0] + '-debug.png'), 'PNG')
@@ -182,7 +182,7 @@ def splitImage(work):
if pageHeight > 15: if pageHeight > 15:
newPage = Image.new('RGB', (widthImg, pageHeight)) newPage = Image.new('RGB', (widthImg, pageHeight))
for panel in page: for panel in page:
panelImg = imgOrg.crop([0, panelsProcessed[panel][0], widthImg, panelsProcessed[panel][1]]) panelImg = imgOrg.crop((0, panelsProcessed[panel][0], widthImg, panelsProcessed[panel][1]))
newPage.paste(panelImg, (0, targetHeight)) newPage.paste(panelImg, (0, targetHeight))
targetHeight += panelsProcessed[panel][2] targetHeight += panelsProcessed[panel][2]
newPage.save(os.path.join(path, os.path.splitext(name)[0] + '-' + str(pageNumber) + '.png'), 'PNG') newPage.save(os.path.join(path, os.path.splitext(name)[0] + '-' + str(pageNumber) + '.png'), 'PNG')
@@ -193,97 +193,100 @@ def splitImage(work):
def main(argv=None, qtgui=None): def main(argv=None, qtgui=None):
global options, GUI, splitWorkerPool, splitWorkerOutput, mergeWorkerPool, mergeWorkerOutput global args, GUI, splitWorkerPool, splitWorkerOutput, mergeWorkerPool, mergeWorkerOutput
parser = OptionParser(usage="Usage: kcc-c2p [options] comic_folder", add_help_option=False) parser = ArgumentParser(prog="kcc-c2p", usage="kcc-c2p [options] [input]", add_help=False)
mainOptions = OptionGroup(parser, "MANDATORY")
otherOptions = OptionGroup(parser, "OTHER") mandatory_options = parser.add_argument_group("MANDATORY")
mainOptions.add_option("-y", "--height", type="int", dest="height", default=0, main_options = parser.add_argument_group("MAIN")
help="Height of the target device screen") other_options = parser.add_argument_group("OTHER")
mainOptions.add_option("-i", "--in-place", action="store_true", dest="inPlace", default=False, mandatory_options.add_argument("input", action="extend", nargs="*", default=None,
help="Overwrite source directory") help="Full path to comic folder(s) to be processed. Separate multiple inputs"
mainOptions.add_option("-m", "--merge", action="store_true", dest="merge", default=False, " with spaces.")
help="Combine every directory into a single image before splitting") main_options.add_argument("-y", "--height", type=int, dest="height", default=0,
otherOptions.add_option("-d", "--debug", action="store_true", dest="debug", default=False, help="Height of the target device screen")
help="Create debug file for every split image") main_options.add_argument("-i", "--in-place", action="store_true", dest="inPlace", default=False,
otherOptions.add_option("-h", "--help", action="help", help="Overwrite source directory")
help="Show this help message and exit") main_options.add_argument("-m", "--merge", action="store_true", dest="merge", default=False,
parser.add_option_group(mainOptions) help="Combine every directory into a single image before splitting")
parser.add_option_group(otherOptions) other_options.add_argument("-d", "--debug", action="store_true", dest="debug", default=False,
options, args = parser.parse_args(argv) help="Create debug file for every split image")
other_options.add_argument("-h", "--help", action="help",
help="Show this help message and exit")
args = parser.parse_args(argv)
if qtgui: if qtgui:
GUI = qtgui GUI = qtgui
else: else:
GUI = None GUI = None
if len(args) != 1: if not argv or args.input == []:
parser.print_help() parser.print_help()
return 1 return 1
if options.height > 0: if args.height > 0:
options.sourceDir = args[0] for sourceDir in args.input:
options.targetDir = args[0] + "-Splitted" targetDir = sourceDir + "-Splitted"
if os.path.isdir(options.sourceDir): if os.path.isdir(sourceDir):
rmtree(options.targetDir, True) rmtree(targetDir, True)
copytree(options.sourceDir, options.targetDir) copytree(sourceDir, targetDir)
work = [] work = []
pagenumber = 1 pagenumber = 1
splitWorkerOutput = [] splitWorkerOutput = []
splitWorkerPool = Pool(maxtasksperchild=10) splitWorkerPool = Pool(maxtasksperchild=10)
if options.merge: if args.merge:
print("Merging images...") print("Merging images...")
directoryNumer = 1 directoryNumer = 1
mergeWork = [] mergeWork = []
mergeWorkerOutput = [] mergeWorkerOutput = []
mergeWorkerPool = Pool(maxtasksperchild=10) mergeWorkerPool = Pool(maxtasksperchild=10)
mergeWork.append([options.targetDir]) mergeWork.append([targetDir])
for root, dirs, files in os.walk(options.targetDir, False): for root, dirs, files in os.walk(targetDir, False):
dirs, files = walkSort(dirs, files) dirs, files = walkSort(dirs, files)
for directory in dirs: for directory in dirs:
directoryNumer += 1 directoryNumer += 1
mergeWork.append([os.path.join(root, directory)]) mergeWork.append([os.path.join(root, directory)])
if GUI:
GUI.progressBarTick.emit('Combining images')
GUI.progressBarTick.emit(str(directoryNumer))
for i in mergeWork:
mergeWorkerPool.apply_async(func=mergeDirectory, args=(i, ), callback=mergeDirectoryTick)
mergeWorkerPool.close()
mergeWorkerPool.join()
if GUI and not GUI.conversionAlive:
rmtree(targetDir, True)
raise UserWarning("Conversion interrupted.")
if len(mergeWorkerOutput) > 0:
rmtree(targetDir, True)
raise RuntimeError("One of workers crashed. Cause: " + mergeWorkerOutput[0][0],
mergeWorkerOutput[0][1])
print("Splitting images...")
for root, _, files in os.walk(targetDir, False):
for name in files:
if getImageFileName(name) is not None:
pagenumber += 1
work.append([root, name, args])
else:
os.remove(os.path.join(root, name))
if GUI: if GUI:
GUI.progressBarTick.emit('Combining images') GUI.progressBarTick.emit('Splitting images')
GUI.progressBarTick.emit(str(directoryNumer)) GUI.progressBarTick.emit(str(pagenumber))
for i in mergeWork: GUI.progressBarTick.emit('tick')
mergeWorkerPool.apply_async(func=mergeDirectory, args=(i, ), callback=mergeDirectoryTick) if len(work) > 0:
mergeWorkerPool.close() for i in work:
mergeWorkerPool.join() splitWorkerPool.apply_async(func=splitImage, args=(i, ), callback=splitImageTick)
if GUI and not GUI.conversionAlive: splitWorkerPool.close()
rmtree(options.targetDir, True) splitWorkerPool.join()
raise UserWarning("Conversion interrupted.") if GUI and not GUI.conversionAlive:
if len(mergeWorkerOutput) > 0: rmtree(targetDir, True)
rmtree(options.targetDir, True) raise UserWarning("Conversion interrupted.")
raise RuntimeError("One of workers crashed. Cause: " + mergeWorkerOutput[0][0], if len(splitWorkerOutput) > 0:
mergeWorkerOutput[0][1]) rmtree(targetDir, True)
print("Splitting images...") raise RuntimeError("One of workers crashed. Cause: " + splitWorkerOutput[0][0],
for root, _, files in os.walk(options.targetDir, False): splitWorkerOutput[0][1])
for name in files: if args.inPlace:
if getImageFileName(name) is not None: rmtree(sourceDir)
pagenumber += 1 move(targetDir, sourceDir)
work.append([root, name, options]) else:
else: rmtree(targetDir, True)
os.remove(os.path.join(root, name)) raise UserWarning("Source directory is empty.")
if GUI:
GUI.progressBarTick.emit('Splitting images')
GUI.progressBarTick.emit(str(pagenumber))
GUI.progressBarTick.emit('tick')
if len(work) > 0:
for i in work:
splitWorkerPool.apply_async(func=splitImage, args=(i, ), callback=splitImageTick)
splitWorkerPool.close()
splitWorkerPool.join()
if GUI and not GUI.conversionAlive:
rmtree(options.targetDir, True)
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])
if options.inPlace:
rmtree(options.sourceDir)
move(options.targetDir, options.sourceDir)
else: else:
rmtree(options.targetDir, True) raise UserWarning("Provided input is not a directory.")
raise UserWarning("Source directory is empty.")
else:
raise UserWarning("Provided path is not a directory.")
else: else:
raise UserWarning("Target height is not set.") raise UserWarning("Target height is not set.")

View File

@@ -55,7 +55,7 @@ class ComicArchive:
def extract(self, targetdir): def extract(self, targetdir):
if not os.path.isdir(targetdir): if not os.path.isdir(targetdir):
raise OSError('Target directory don\'t exist.') raise OSError('Target directory doesn\'t exist.')
process = Popen('7z x -y -xr!__MACOSX -xr!.DS_Store -xr!thumbs.db -xr!Thumbs.db -o"' + targetdir + '" "' + process = Popen('7z x -y -xr!__MACOSX -xr!.DS_Store -xr!thumbs.db -xr!Thumbs.db -o"' + targetdir + '" "' +
self.filepath + '"', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True) self.filepath + '"', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
process.communicate() process.communicate()