diff --git a/kcc/KCC_gui.py b/kcc/KCC_gui.py index 0f53788..fe5954c 100644 --- a/kcc/KCC_gui.py +++ b/kcc/KCC_gui.py @@ -1335,14 +1335,10 @@ class KCCGUI_MetaEditor(KCC_MetaEditor_ui.Ui_MetaEditorDialog): self.EditorFrame.setEnabled(True) self.OKButton.setEnabled(True) self.StatusLabel.setText('Separate authors with a comma.') - self.SeriesLine.setText(self.parser.data['Series']) - self.VolumeLine.setText(self.parser.data['Volume']) - self.NumberLine.setText(self.parser.data['Number']) - self.WriterLine.setText(', '.join(self.parser.data['Writers'])) - self.PencillerLine.setText(', '.join(self.parser.data['Pencillers'])) - self.InkerLine.setText(', '.join(self.parser.data['Inkers'])) - self.ColoristLine.setText(', '.join(self.parser.data['Colorists'])) - self.MUidLine.setText(self.parser.data['MUid']) + for field in (self.SeriesLine, self.VolumeLine, self.NumberLine, self.MUidLine): + field.setText(self.parser.data[field.objectName()[:-4]]) + for field in (self.WriterLine, self.PencillerLine, self.InkerLine, self.ColoristLine): + field.setText(', '.join(self.parser.data[field.objectName()[:-4] + 's'])) def saveData(self): for field in (self.VolumeLine, self.NumberLine, self.MUidLine): diff --git a/kcc/comic2ebook.py b/kcc/comic2ebook.py index eadaf4f..e72d911 100755 --- a/kcc/comic2ebook.py +++ b/kcc/comic2ebook.py @@ -75,6 +75,7 @@ def main(argv=None): def buildHTML(path, imgfile, imgfilepath, forcePV=False): imgfilepath = md5Checksum(imgfilepath) filename = getImageFileName(imgfile) + additionalStyle = '' if options.imgproc: if "Rotated" in options.imgIndex[imgfilepath]: rotatedPage = True @@ -92,6 +93,8 @@ def buildHTML(path, imgfile, imgfilepath, forcePV=False): noVerticalPV = True else: noVerticalPV = False + if "BlackFill" in options.imgIndex[imgfilepath]: + additionalStyle = ' style="background-color:#000000" ' else: rotatedPage = False noPV = False @@ -125,7 +128,7 @@ def buildHTML(path, imgfile, imgfilepath, forcePV=False): "\n", "\n", - "\n", + "\n", "
\n", "
\"",
\n" @@ -169,7 +172,7 @@ def buildHTML(path, imgfile, imgfilepath, forcePV=False): f.writelines(["
\n"]) - if options.quality == 2: + if options.quality == 2 and not forcePV: imgfilepv = imgfile.split(".") imgfilepv[0] += "-hq" imgfilepv = ".".join(imgfilepv) @@ -433,6 +436,7 @@ def buildEPUB(path, chapterNames, tomeNumber): cover = os.path.join(os.path.join(path, 'OEBPS', 'Images'), 'cover' + getImageFileName(filelist[-1][1])[1]) image.Cover(os.path.join(filelist[-1][0], filelist[-1][1]), cover, options, tomeNumber) + # Hack that force Panel View on at last one page if lastfile and not options.panelviewused and 'Ko' not in options.profile \ and options.profile not in ['K1', 'K2', 'KDX', 'OTHER']: filelist[-1] = buildHTML(lastfile[0], lastfile[1], lastfile[2], True) @@ -444,24 +448,17 @@ def buildEPUB(path, chapterNames, tomeNumber): buildOPF(path, options.title, filelist, cover) -def imgOptimization(img, opt, hqImage=None): +def imgOptimization(img, opt): if not img.fill: img.getImageFill() if not opt.webtoon: img.cropWhiteSpace() if opt.cutpagenumbers and not opt.webtoon: img.cutPageNumber() - img.optimizeImage() - if hqImage: - img.resizeImage(0) - img.calculateBorder(hqImage, True) - else: - img.resizeImage() - if opt.panelview: - if opt.quality == 0: - img.calculateBorder(img) - elif opt.quality == 1: - img.calculateBorder(img, True) + img.autocontrastImage() + img.resizeImage() + if not img.second and opt.panelview: + img.calculateBorder() if opt.forcepng and not opt.forcecolor: img.quantizeImage() @@ -523,10 +520,6 @@ def imgFileProcessing(work): opt = work[2] output = [] img = image.ComicPage(os.path.join(dirpath, afile), opt) - if opt.quality == 2: - wipe = False - else: - wipe = True if opt.nosplitrotate: splitter = None else: @@ -534,36 +527,30 @@ def imgFileProcessing(work): if splitter is not None: img0 = image.ComicPage(splitter[0], opt) imgOptimization(img0, opt) - output.append(img0.saveToDir(dirpath)) + if not img0.noHQ: + output.append(img0.saveToDir(dirpath)) img1 = image.ComicPage(splitter[1], opt) imgOptimization(img1, opt) - output.append(img1.saveToDir(dirpath)) - if wipe: - output.append(img0.origFileName) - output.append(img1.origFileName) + if not img1.noHQ: + output.append(img1.saveToDir(dirpath)) + output.extend([img.origFileName, img0.origFileName, img1.origFileName]) if opt.quality == 2: - img0b = image.ComicPage(splitter[0], opt, img0.fill) - imgOptimization(img0b, opt, img0) + output.extend([img0.origFileName, img1.origFileName]) + img0b = image.ComicPage(splitter[0], opt, img0) + imgOptimization(img0b, opt) output.append(img0b.saveToDir(dirpath)) - img1b = image.ComicPage(splitter[1], opt, img1.fill) - imgOptimization(img1b, opt, img1) + img1b = image.ComicPage(splitter[1], opt, img1) + imgOptimization(img1b, opt) output.append(img1b.saveToDir(dirpath)) - output.append(img0.origFileName) - output.append(img1.origFileName) - output.append(img.origFileName) else: + output.append(img.origFileName) imgOptimization(img, opt) - output.append(img.saveToDir(dirpath)) - if wipe: - output.append(img.origFileName) + if not img.noHQ: + output.append(img.saveToDir(dirpath)) if opt.quality == 2: - img2 = image.ComicPage(os.path.join(dirpath, afile), opt, img.fill) - if img.rotated: - img2.image = img2.image.rotate(90, Image.BICUBIC, True) - img2.rotated = True - imgOptimization(img2, opt, img) + img2 = image.ComicPage(os.path.join(dirpath, afile), opt, img) + imgOptimization(img2, opt) output.append(img2.saveToDir(dirpath)) - output.append(img.origFileName) return output except Exception: return str(sys.exc_info()[1]) @@ -575,7 +562,7 @@ def getWorkFolder(afile): if os.path.isdir(afile): workdir = mkdtemp('', 'KCC-TMP-') try: - os.rmdir(workdir) # needed for copytree() fails if dst already exists + os.rmdir(workdir) fullPath = os.path.join(workdir, 'OEBPS', 'Images') if len(fullPath) > 240: raise UserWarning("Path is too long.") @@ -906,20 +893,20 @@ def detectMargins(path): yu = flag[2] xr = flag[3] yd = flag[4] - if xl != "0": - xl = "-" + str(float(xl)/100) + "%" + if xl != "0.0": + xl = "-" + xl + "%" else: xl = "0%" - if xr != "0": - xr = "-" + str(float(xr)/100) + "%" + if xr != "0.0": + xr = "-" + xr + "%" else: xr = "0%" - if yu != "0": - yu = "-" + str(float(yu)/100) + "%" + if yu != "0.0": + yu = "-" + yu + "%" else: yu = "0%" - if yd != "0": - yd = "-" + str(float(yd)/100) + "%" + if yd != "0.0": + yd = "-" + yd + "%" else: yd = "0%" return xl, yu, xr, yd @@ -1123,10 +1110,7 @@ def makeBook(source, qtGUI=None): getComicInfo(os.path.join(path, "OEBPS", "Images"), source) detectCorruption(os.path.join(path, "OEBPS", "Images"), source) if options.webtoon: - if options.customheight > 0: - comic2panel.main(['-y ' + str(options.customheight), '-i', '-m', path], qtGUI) - else: - comic2panel.main(['-y ' + str(image.ProfileData.Profiles[options.profile][1][1]), '-i', '-m', path], qtGUI) + comic2panel.main(['-y ' + str(image.ProfileData.Profiles[options.profile][1][1]), '-i', '-m', path], qtGUI) if options.imgproc: print("\nProcessing images...") if GUI: diff --git a/kcc/image.py b/kcc/image.py index 8ba8f09..d830e79 100755 --- a/kcc/image.py +++ b/kcc/image.py @@ -98,7 +98,7 @@ class ProfileData: class ComicPage: - def __init__(self, source, options, fill=None): + def __init__(self, source, options, original=None): try: self.profile_label, self.size, self.palette, self.gamma, self.panelviewsize = options.profileData except KeyError: @@ -107,58 +107,67 @@ class ComicPage: self.filename = os.path.basename(self.origFileName) self.image = Image.open(source) self.image = self.image.convert('RGB') - self.rotated = None - self.border = None - self.noHPV = None - self.noVPV = None - self.noPV = None - self.purge = False - self.hq = False self.opt = options - if fill: - self.fill = fill + if original: + self.second = True + self.rotated = original.rotated + self.border = original.border + self.noHPV = original.noHPV + self.noVPV = original.noVPV + self.noPV = original.noPV + self.noHQ = original.noHQ + self.fill = original.fill + self.color = original.color + if self.rotated: + self.image = self.image.rotate(90, Image.BICUBIC, True) + self.opt.quality = 0 else: + self.second = False + self.rotated = None + self.border = None + self.noHPV = None + self.noVPV = None + self.noPV = None self.fill = None - if options.webtoon: - self.color = True - else: - self.color = self.isImageColor() + self.noHQ = False + if options.webtoon: + self.color = True + else: + self.color = self.isImageColor() def saveToDir(self, targetdir): try: - if not self.purge: - flags = [] - filename = os.path.join(targetdir, os.path.splitext(self.filename)[0]) + '-KCC' - if not self.opt.forcecolor and not self.opt.forcepng: - self.image = self.image.convert('L') - if self.rotated: - flags.append('Rotated') - if self.hq: - flags.append('HighQuality') - filename += '-HQ' - if self.noPV: - flags.append('NoPanelView') - else: - if self.noHPV: - flags.append('NoHorizontalPanelView') - if self.noVPV: - flags.append('NoVerticalPanelView') - if self.border: - flags.append('Margins-' + str(self.border[0]) + '-' + str(self.border[1]) + '-' - + str(self.border[2]) + '-' + str(self.border[3])) - if self.opt.forcepng: - filename += '.png' - self.image.save(filename, 'PNG', optimize=1) - else: - filename += '.jpg' - self.image.save(filename, 'JPEG', optimize=1, quality=80) - return [md5Checksum(filename), flags] + flags = [] + filename = os.path.join(targetdir, os.path.splitext(self.filename)[0]) + '-KCC' + if not self.opt.forcecolor and not self.opt.forcepng: + self.image = self.image.convert('L') + if self.rotated: + flags.append('Rotated') + if self.noPV: + flags.append('NoPanelView') else: - return None + if self.noHPV: + flags.append('NoHorizontalPanelView') + if self.noVPV: + flags.append('NoVerticalPanelView') + if self.border: + flags.append('Margins-' + str(self.border[0]) + '-' + str(self.border[1]) + '-' + + str(self.border[2]) + '-' + str(self.border[3])) + if self.fill != 'white': + flags.append('BlackFill') + if self.opt.quality == 2: + filename += '-HQ' + if self.opt.forcepng: + filename += '.png' + self.image.save(filename, 'PNG', optimize=1) + else: + filename += '.jpg' + self.image.save(filename, 'JPEG', optimize=1, quality=80) + return [md5Checksum(filename), flags] except IOError as e: raise RuntimeError('Cannot write image in directory %s: %s' % (targetdir, e)) - def optimizeImage(self): + def autocontrastImage(self): gamma = self.opt.gamma if gamma < 0.1: gamma = self.gamma @@ -180,80 +189,65 @@ class ComicPage: # Quantize is deprecated but new function call it internally anyway... self.image = self.image.quantize(palette=palImg) - def calculateBorderPercent(self, x, img, isWidth): - if isWidth: - return int(round(float(x)/float(img.image.size[0]), 4) * 10000 * 1.5) - else: - return int(round(float(x)/float(img.image.size[1]), 4) * 10000 * 1.5) - - def calculateBorder(self, sourceImage, isHQ=False): - if (isHQ and sourceImage.purge) or self.noPV: - self.border = [0, 0, 0, 0] - self.noPV = True + def calculateBorder(self): + if self.noPV: + self.border = [0.0, 0.0, 0.0, 0.0] return if self.fill == 'white': - # Only already saved files can have P mode. So we can break color quantization. - if sourceImage.image.mode == 'P': - sourceImage.image = sourceImage.image.convert('RGB') - border = ImageChops.invert(sourceImage.image).getbbox() + border = ImageChops.invert(self.image).getbbox() else: - border = sourceImage.image.getbbox() + border = self.image.getbbox() + if self.opt.quality == 2: + multiplier = 1.0 + else: + multiplier = 1.5 if border is not None: - if isHQ: - multiplier = 1.0 - else: - multiplier = 1.5 - self.border = [self.calculateBorderPercent(border[0], sourceImage, True), - self.calculateBorderPercent(border[1], sourceImage, False), - self.calculateBorderPercent((sourceImage.image.size[0] - border[2]), sourceImage, True), - self.calculateBorderPercent((sourceImage.image.size[1] - border[3]), sourceImage, False)] - if int((border[2] - border[0]) * multiplier) < self.size[0]: + self.border = [round(float(border[0])/float(self.image.size[0])*150, 3), + round(float(border[1])/float(self.image.size[1])*150, 3), + round(float(self.image.size[0]-border[2])/float(self.image.size[0])*150, 3), + round(float(self.image.size[1]-border[3])/float(self.image.size[1])*150, 3)] + if int((border[2] - border[0]) * multiplier) < self.size[0] + 10: self.noHPV = True - if int((border[3] - border[1]) * multiplier) < self.size[1]: + if int((border[3] - border[1]) * multiplier) < self.size[1] + 10: self.noVPV = True else: - self.border = [0, 0, 0, 0] + self.border = [0.0, 0.0, 0.0, 0.0] self.noHPV = True self.noVPV = True - def resizeImage(self, qualityMode=None): - upscale = self.opt.upscale - stretch = self.opt.stretch - bordersColor = self.opt.bordersColor - if qualityMode is None: - qualityMode = self.opt.quality - if bordersColor: - fill = bordersColor + def resizeImage(self): + if self.opt.bordersColor: + fill = self.opt.bordersColor else: fill = self.fill # Set target size - if qualityMode == 0: + if self.opt.quality == 0: size = (self.size[0], self.size[1]) - elif qualityMode == 1 and not stretch and not upscale and self.image.size[0] <=\ + elif self.opt.quality == 1 and not self.opt.stretch and not self.opt.upscale and self.image.size[0] <=\ self.size[0] and self.image.size[1] <= self.size[1]: size = (self.size[0], self.size[1]) - elif qualityMode == 1: + elif self.opt.quality == 1: # Forcing upscale to make sure that margins will be not too big - if not stretch: - upscale = True + if not self.opt.stretch: + self.opt.upscale = True size = (self.panelviewsize[0], self.panelviewsize[1]) - elif qualityMode == 2 and not stretch and not upscale and self.image.size[0] <=\ + elif self.opt.quality == 2 and not self.opt.stretch and not self.opt.upscale and self.image.size[0] <=\ self.size[0] and self.image.size[1] <= self.size[1]: - self.purge = True - return self.image + # HQ version will not be needed + self.noHQ = True + return else: - self.hq = True size = (self.panelviewsize[0], self.panelviewsize[1]) # If stretching is on - Resize without other considerations - if stretch: + if self.opt.stretch: if self.image.size[0] <= size[0] and self.image.size[1] <= size[1]: method = Image.BICUBIC else: method = Image.LANCZOS self.image = self.image.resize(size, method) - return self.image + return # If image is smaller than target resolution and upscale is off - Just expand it by adding margins - if self.image.size[0] <= size[0] and self.image.size[1] <= size[1] and not upscale: + if self.image.size[0] <= size[0] and self.image.size[1] <= size[1] and not self.opt.upscale: borderw = int((size[0] - self.image.size[0]) / 2) borderh = int((size[1] - self.image.size[1]) / 2) # PV is disabled when source image is smaller than device screen and upscale is off @@ -263,7 +257,7 @@ class ComicPage: # Border can't be float so sometimes image might be 1px too small/large if self.image.size[0] != size[0] or self.image.size[1] != size[1]: self.image = ImageOps.fit(self.image, size, method=Image.BICUBIC, centering=(0.5, 0.5)) - return self.image + return # Otherwise - Upscale/Downscale ratioDev = float(size[0]) / float(size[1]) if (float(self.image.size[0]) / float(self.image.size[1])) < ratioDev: @@ -277,7 +271,7 @@ class ComicPage: else: method = Image.LANCZOS self.image = ImageOps.fit(self.image, size, method=method, centering=(0.5, 0.5)) - return self.image + return def splitPage(self, targetdir): width, height = self.image.size @@ -370,7 +364,6 @@ class ComicPage: else: diff = pageNumberCut1 self.image = self.image.crop((0, 0, widthImg, heightImg - diff)) - return self.image def cropWhiteSpace(self): if ImageChops.invert(self.image).getbbox() is not None: @@ -406,7 +399,6 @@ class ComicPage: diff += delta diff -= delta self.image = self.image.crop((0, 0, widthImg - diff, heightImg)) - return self.image def getImageHistogram(self, image): histogram = image.histogram() diff --git a/kcc/metadata.py b/kcc/metadata.py index d17b877..8070d52 100644 --- a/kcc/metadata.py +++ b/kcc/metadata.py @@ -69,7 +69,7 @@ class MetadataParser: stdout=PIPE, stderr=STDOUT, shell=True) extracted = False for line in output.stdout: - if b"Everything is Ok" in line: + if b"Everything is Ok" in line or b"No files to process" in line: extracted = True if not extracted: rmtree(workdir) diff --git a/kcc/shared.py b/kcc/shared.py index 4558fa1..f31bb25 100644 --- a/kcc/shared.py +++ b/kcc/shared.py @@ -20,11 +20,14 @@ import os from hashlib import md5 from html.parser import HTMLParser from distutils.version import StrictVersion -from scandir import walk from time import sleep from shutil import rmtree, move from tempfile import mkdtemp from zipfile import ZipFile, ZIP_DEFLATED +try: + from scandir import walk +except ImportError: + walk = None class HTMLStripper(HTMLParser):