From b545f7ad48319c8236a14c422fe7eb22c6bb6d8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Jastrz=C4=99bski?= Date: Sun, 13 Nov 2016 07:30:51 +0100 Subject: [PATCH 1/8] Small tweaks --- kcc/KCC_gui.py | 4 +++- kcc/comic2ebook.py | 25 +------------------------ kcc/shared.py | 3 +-- 3 files changed, 5 insertions(+), 27 deletions(-) diff --git a/kcc/KCC_gui.py b/kcc/KCC_gui.py index c773529..22052bb 100644 --- a/kcc/KCC_gui.py +++ b/kcc/KCC_gui.py @@ -603,7 +603,9 @@ class KCCGUI(KCC_ui.Ui_mainWindow): GUI.upscaleBox.setEnabled(False) GUI.upscaleBox.setChecked(True) else: - GUI.qualityBox.setEnabled(True) + profile = GUI.profiles[str(GUI.deviceBox.currentText())] + if profile['Quality']: + GUI.qualityBox.setEnabled(True) GUI.mangaBox.setEnabled(True) GUI.rotateBox.setEnabled(True) GUI.upscaleBox.setEnabled(True) diff --git a/kcc/comic2ebook.py b/kcc/comic2ebook.py index a303739..52c6343 100755 --- a/kcc/comic2ebook.py +++ b/kcc/comic2ebook.py @@ -336,29 +336,6 @@ def buildOPF(dstdir, title, filelist, cover=None): f.write("\n\n") else: f.write("\n\n") - # if options.iskindle and options.profile != 'Custom': - # if options.righttoleft: - # nextflow = 'right' - # else: - # nextflow = 'left' - # for entry in reflist: - # if '-kcc-b' in entry: - # if options.righttoleft: - # f.write("\n") - # else: - # f.write("\n") - # elif '-kcc-c' in entry: - # if options.righttoleft: - # f.write("\n") - # else: - # f.write("\n") - # else: - # f.write("\n") - # if nextflow == 'right': - # nextflow = 'left' - # else: - # nextflow = 'right' - # else: for entry in reflist: f.write("\n") f.write("\n\n") @@ -1184,7 +1161,6 @@ def makeBook(source, qtGUI=None): if not GUI and options.format == 'MOBI': print("Creating MOBI files...") work = [] - k = kindle.Kindle() for i in filepath: work.append([i]) output = makeMOBI(work, GUI) @@ -1193,6 +1169,7 @@ def makeBook(source, qtGUI=None): print('Error: KindleGen failed to create MOBI!') print(errors) return filepath + k = kindle.Kindle() if k.path and k.coverSupport: print("Kindle detected. Uploading covers...") for i in filepath: diff --git a/kcc/shared.py b/kcc/shared.py index c149502..88d1782 100644 --- a/kcc/shared.py +++ b/kcc/shared.py @@ -144,8 +144,7 @@ def removeFromZIP(zipfname, *filenames): def sanitizeTrace(traceback): return ''.join(format_tb(traceback))\ - .replace('C:\\Users\\pawel\\Documents\\Projekty\\KCC\\', '') \ - .replace('C:\\Users\\Paweł\\Documents\\Projekty\\KCC\\', '') \ + .replace('C:\\Users\\Pawel\\Documents\\Projekty\\KCC\\', '') \ .replace('C:\\Python35\\', '')\ .replace('c:\\python35\\', '') From d1a07d7ffaaa426fa9171b43f2cf235fe46e9427 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Jastrz=C4=99bski?= Date: Sat, 19 Nov 2016 17:57:16 +0100 Subject: [PATCH 2/8] Improved cropping mechanism --- kcc/comic2ebook.py | 16 +++--- kcc/image.py | 120 +++++++++++++-------------------------------- 2 files changed, 41 insertions(+), 95 deletions(-) diff --git a/kcc/comic2ebook.py b/kcc/comic2ebook.py index 52c6343..34c8b0a 100755 --- a/kcc/comic2ebook.py +++ b/kcc/comic2ebook.py @@ -525,10 +525,10 @@ def imgFileProcessing(work): workImg = image.ComicPageParser((dirpath, afile), opt) for i in workImg.payload: img = image.ComicPage(i[0], i[1], i[2], i[3], i[4], opt) - if opt.cropping > 0 and not opt.webtoon: - img.cropWhiteSpace(opt.croppingp) if opt.cropping == 2 and not opt.webtoon: - img.cutPageNumber(opt.croppingpn) + img.cropPageNumber(opt.croppingp) + if opt.cropping > 0 and not opt.webtoon: + img.cropMargin(opt.croppingp) img.autocontrastImage() img.resizeImage() if opt.forcepng and not opt.forcecolor: @@ -960,6 +960,10 @@ def makeParser(): help="Double page parsing mode. 0: Split 1: Rotate 2: Both [Default=0]") processingOptions.add_option("-g", "--gamma", type="float", dest="gamma", default="0.0", help="Apply gamma correction to linearize the image [Default=Auto]") + 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("--hq", action="store_true", dest="hqmode", default=False, help="Enable high quality Panel View") processingOptions.add_option("--blackborders", action="store_true", dest="black_borders", default=False, @@ -970,12 +974,6 @@ def makeParser(): 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("--cropping", type="int", dest="cropping", default="2", - help="Set cropping mode. 0: Disabled 1: Margins 2: Margins + page numbers [Default=2]") - processingOptions.add_option("--croppingpower", type="float", dest="croppingp", default="0.1", - help="Set margin cropping threshold [Default=0.1]") - processingOptions.add_option("--croppingpowerpage", type="float", dest="croppingpn", default="5.0", - help="Set page number cropping threshold [Default=5.0]") customProfileOptions.add_option("--customwidth", type="int", dest="customwidth", default=0, help="Replace screen width provided by device profile") diff --git a/kcc/image.py b/kcc/image.py index aef77e5..3101b99 100755 --- a/kcc/image.py +++ b/kcc/image.py @@ -1,5 +1,6 @@ # Copyright (C) 2010 Alex Yatskov # Copyright (C) 2011 Stanislav (proDOOMman) Kosolapov +# Copyright (c) 2016 Alberto Planas # Copyright (c) 2012-2014 Ciro Mattia Gonano # Copyright (c) 2013-2016 Pawel Jastrzebski # @@ -20,7 +21,7 @@ import os from io import BytesIO from urllib.request import Request, urlopen from urllib.parse import quote -from PIL import Image, ImageOps, ImageStat, ImageChops +from PIL import Image, ImageOps, ImageStat, ImageChops, ImageFilter from .shared import md5Checksum from . import __version__ @@ -318,92 +319,39 @@ class ComicPage: if self.image.size[0] > size[0] or self.image.size[1] > size[1]: self.image.thumbnail(size, Image.LANCZOS) - def cutPageNumber(self, fixedThreshold): - if ImageChops.invert(self.image).getbbox() is not None: - widthImg, heightImg = self.image.size - delta = 2 - diff = delta - if ImageStat.Stat(self.image).var[0] < 2 * fixedThreshold: - return self.image - while ImageStat.Stat(self.image.crop((0, heightImg - diff, widthImg, heightImg))).var[0] < fixedThreshold\ - and diff < heightImg: - diff += delta - diff -= delta - pageNumberCut1 = diff - if diff < delta: - diff = delta - oldStat = ImageStat.Stat(self.image.crop((0, heightImg - diff, widthImg, heightImg))).var[0] - diff += delta - while ImageStat.Stat(self.image.crop((0, heightImg - diff, widthImg, heightImg))).var[0] - oldStat > 0\ - and diff < heightImg // 4: - oldStat = ImageStat.Stat(self.image.crop((0, heightImg - diff, widthImg, heightImg))).var[0] - diff += delta - diff -= delta - pageNumberCut2 = diff - diff += delta - oldStat = ImageStat.Stat(self.image.crop((0, heightImg - diff, widthImg, - heightImg - pageNumberCut2))).var[0] - while ImageStat.Stat(self.image.crop((0, heightImg - diff, widthImg, heightImg - pageNumberCut2))).var[0]\ - < fixedThreshold + oldStat and diff < heightImg // 4: - diff += delta - diff -= delta - pageNumberCut3 = diff - delta = 5 - diff = delta - while ImageStat.Stat(self.image.crop((0, heightImg - pageNumberCut2, diff, heightImg))).var[0]\ - < fixedThreshold and diff < widthImg: - diff += delta - diff -= delta - pageNumberX1 = diff - diff = delta - while ImageStat.Stat(self.image.crop((widthImg - diff, heightImg - pageNumberCut2, - widthImg, heightImg))).var[0] < fixedThreshold and diff < widthImg: - diff += delta - diff -= delta - pageNumberX2 = widthImg - diff - if pageNumberCut3 - pageNumberCut1 > 2 * delta\ - and float(pageNumberX2 - pageNumberX1) / float(pageNumberCut2 - pageNumberCut1) <= 9.0\ - and ImageStat.Stat(self.image.crop((0, heightImg - pageNumberCut3, widthImg, heightImg))).var[0]\ - / ImageStat.Stat(self.image).var[0] < 0.1\ - and pageNumberCut3 < heightImg / 4 - delta: - diff = pageNumberCut3 - else: - diff = pageNumberCut1 - self.image = self.image.crop((0, 0, widthImg, heightImg - diff)) + def getBoundingBox(self, tmpImg): + min_margin = [int(0.005 * i + 0.5) for i in tmpImg.size] + max_margin = [int(0.1 * i + 0.5) for i in tmpImg.size] + bbox = tmpImg.getbbox() + bbox = ( + max(0, min(max_margin[0], bbox[0] - min_margin[0])), + max(0, min(max_margin[1], bbox[1] - min_margin[1])), + min(tmpImg.size[0], + max(tmpImg.size[0] - max_margin[0], bbox[2] + min_margin[0])), + min(tmpImg.size[1], + max(tmpImg.size[1] - max_margin[1], bbox[3] + min_margin[1])), + ) + return bbox - def cropWhiteSpace(self, fixedThreshold): - if ImageChops.invert(self.image).getbbox() is not None: - widthImg, heightImg = self.image.size - delta = 10 - diff = delta - # top - while ImageStat.Stat(self.image.crop((0, 0, widthImg, diff))).var[0] < fixedThreshold and diff < heightImg: - diff += delta - diff -= delta - self.image = self.image.crop((0, diff, widthImg, heightImg)) - widthImg, heightImg = self.image.size - diff = delta - # left - while ImageStat.Stat(self.image.crop((0, 0, diff, heightImg))).var[0] < fixedThreshold and diff < widthImg: - diff += delta - diff -= delta - self.image = self.image.crop((diff, 0, widthImg, heightImg)) - widthImg, heightImg = self.image.size - diff = delta - # down - while ImageStat.Stat(self.image.crop((0, heightImg - diff, widthImg, heightImg))).var[0] < fixedThreshold\ - and diff < heightImg: - diff += delta - diff -= delta - self.image = self.image.crop((0, 0, widthImg, heightImg - diff)) - widthImg, heightImg = self.image.size - diff = delta - # right - while ImageStat.Stat(self.image.crop((widthImg - diff, 0, widthImg, heightImg))).var[0] < fixedThreshold\ - and diff < widthImg: - diff += delta - diff -= delta - self.image = self.image.crop((0, 0, widthImg - diff, heightImg)) + def cropPageNumber(self, power): + if self.fill != 'white': + tmpImg = self.image.convert(mode='L') + else: + tmpImg = ImageOps.invert(self.image.convert(mode='L')) + tmpImg = tmpImg.point(lambda x: x and 255) + tmpImg = tmpImg.filter(ImageFilter.MinFilter(size=3)) + tmpImg = tmpImg.filter(ImageFilter.GaussianBlur(radius=5)) + tmpImg = tmpImg.point(lambda x: (x >= 48 * power) and x) + self.image = self.image.crop(tmpImg.getbbox()) if tmpImg.getbbox() else self.image + + def cropMargin(self, power): + if self.fill != 'white': + tmpImg = self.image.convert(mode='L') + else: + tmpImg = ImageOps.invert(self.image.convert(mode='L')) + tmpImg = tmpImg.filter(ImageFilter.GaussianBlur(radius=3)) + tmpImg = tmpImg.point(lambda x: (x >= 16 * power) and x) + self.image = self.image.crop(self.getBoundingBox(tmpImg)) if tmpImg.getbbox() else self.image class Cover: From 9ce691aecb181962134febe8788faa08785eea7a Mon Sep 17 00:00:00 2001 From: Houcheng Lin Date: Sun, 20 Nov 2016 17:38:06 -0500 Subject: [PATCH 3/8] add autoscale option Instead of fixed 1.5 scale ratio, the autoscale feature uses current page's image width, and dynamically determine the needed scale ratio. The rendering effects looks okay and speed is fine in my KPW1. The generated panel view will have two view ports: (top and bottom). --- kcc/comic2ebook.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/kcc/comic2ebook.py b/kcc/comic2ebook.py index a303739..bffc798 100755 --- a/kcc/comic2ebook.py +++ b/kcc/comic2ebook.py @@ -80,6 +80,9 @@ def main(argv=None): makeBook(source) return 0 +def calculateZoomImageSize(imageSize, deviceRes): + scale = float(deviceRes[0])/float(imageSize[0]) + return (float(deviceRes[0]), scale * imageSize[1]) def buildHTML(path, imgfile, imgfilepath): imgfilepath = md5Checksum(imgfilepath) @@ -132,6 +135,8 @@ def buildHTML(path, imgfile, imgfilepath): imgfilepv = imgfile sizeTmp = Image.open(os.path.join(head, "Images", postfix, imgfilepv)).size size = (int(sizeTmp[0] * 1.5), int(sizeTmp[1] * 1.5)) + if options.autoscale: + size = calculateZoomImageSize(sizeTmp, deviceres) if size[0] <= deviceres[0]: noHorizontalPV = True else: @@ -961,6 +966,9 @@ def makeParser(): mainOptions.add_option("-p", "--profile", action="store", dest="profile", default="KV", help="Device profile (Available options: K1, K2, K3, K45, KDX, KPW, KV, KoMT, KoG, KoGHD," " KoA, KoAHD, KoAH2O, KoAO) [Default=KV]") + mainOptions.add_option("-a", "--auto-scale", action="store_true", dest="autoscale", default=False, + help="Auto scale image in panel view by width. The zoom-in mode will have two view ports" + "(top and bottom)") 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("-w", "--webtoon", action="store_true", dest="webtoon", default=False, From 2a2bfae112a069cdf815dd65badb7ee79ea2307d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Jastrz=C4=99bski?= Date: Mon, 21 Nov 2016 13:55:12 +0100 Subject: [PATCH 4/8] Dropped HQ PV option --- kcc/comic2ebook.py | 44 ++++++------------ kcc/image.py | 109 ++++++++++++++++++--------------------------- 2 files changed, 56 insertions(+), 97 deletions(-) diff --git a/kcc/comic2ebook.py b/kcc/comic2ebook.py index 34c8b0a..0633896 100755 --- a/kcc/comic2ebook.py +++ b/kcc/comic2ebook.py @@ -95,8 +95,6 @@ def buildHTML(path, imgfile, imgfilepath): additionalStyle = 'background-color:#FFFFFF;' htmlpath = '' postfix = '' - size = '' - imgfilepv = '' backref = 1 head = path while True: @@ -122,16 +120,8 @@ def buildHTML(path, imgfile, imgfilepath): "\n"]) if options.iskindle and options.panelview: - if options.hqmode: - imgfilepv = list(os.path.splitext(imgfile)) - imgfilepv[0] += "-hq" - imgfilepv = "".join(imgfilepv) - if os.path.isfile(os.path.join(head, "Images", postfix, imgfilepv)): - size = Image.open(os.path.join(head, "Images", postfix, imgfilepv)).size - if not options.hqmode or not size: - imgfilepv = imgfile - sizeTmp = Image.open(os.path.join(head, "Images", postfix, imgfilepv)).size - size = (int(sizeTmp[0] * 1.5), int(sizeTmp[1] * 1.5)) + sizeTmp = Image.open(os.path.join(head, "Images", postfix, imgfile)).size + size = (int(sizeTmp[0] * 1.5), int(sizeTmp[1] * 1.5)) if size[0] <= deviceres[0]: noHorizontalPV = True else: @@ -193,7 +183,7 @@ def buildHTML(path, imgfile, imgfilepath): for box in boxes: f.writelines(["
\n", "\n", + imgfile, "\" width=\"" + str(size[0]) + "\" height=\"" + str(size[1]) + "\"/>\n", "
\n"]) f.writelines(["\n", "\n"]) @@ -437,17 +427,15 @@ def buildEPUB(path, chapterNames, tomeNumber): chapter = False dirnames, filenames = walkSort(dirnames, filenames) for afile in filenames: - filename = getImageFileName(afile) - if not filename[0].endswith('-hq'): - filelist.append(buildHTML(dirpath, afile, os.path.join(dirpath, afile))) - if not chapter: - chapterlist.append((dirpath.replace('Images', 'Text'), filelist[-1][1])) - chapter = True - if cover is None: - cover = os.path.join(os.path.join(path, 'OEBPS', 'Images'), - 'cover' + getImageFileName(filelist[-1][1])[1]) - options.covers.append((image.Cover(os.path.join(filelist[-1][0], filelist[-1][1]), cover, options, - tomeNumber), options.uuid)) + filelist.append(buildHTML(dirpath, afile, os.path.join(dirpath, afile))) + if not chapter: + chapterlist.append((dirpath.replace('Images', 'Text'), filelist[-1][1])) + chapter = True + if cover is None: + cover = os.path.join(os.path.join(path, 'OEBPS', 'Images'), + 'cover' + getImageFileName(filelist[-1][1])[1]) + options.covers.append((image.Cover(os.path.join(filelist[-1][0], filelist[-1][1]), cover, options, + tomeNumber), options.uuid)) # Overwrite chapternames if tree is flat and ComicInfo.xml has bookmarks if not chapterNames and options.chapters: chapterlist = [] @@ -964,8 +952,6 @@ def makeParser(): 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("--hq", action="store_true", dest="hqmode", default=False, - help="Enable high quality Panel View") 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, @@ -1015,20 +1001,16 @@ def checkOptions(): # Older Kindle don't need higher resolution files due lack of Panel View. if options.profile == 'K1' or options.profile == 'K2' or options.profile == 'K3' or options.profile == 'KDX': options.panelview = False - options.hqmode = False # Webtoon mode mandatory options if options.webtoon: options.panelview = False - options.hqmode = False options.righttoleft = False options.upscale = True # Disable all Kindle features for other e-readers if options.profile == 'OTHER': options.panelview = False - options.hqmode = False if 'Ko' in options.profile: options.panelview = False - options.hqmode = False # CBZ files on Kindle DX/DXG support higher resolution if options.profile == 'KDX' and options.format == 'CBZ': options.customheight = 1200 @@ -1041,7 +1023,7 @@ def checkOptions(): if options.customheight != 0: Y = options.customheight newProfile = ("Custom", (int(X), int(Y)), image.ProfileData.Palette16, - image.ProfileData.Profiles[options.profile][3], (int(int(X) * 1.5), int(int(Y) * 1.5))) + image.ProfileData.Profiles[options.profile][3]) image.ProfileData.Profiles["Custom"] = newProfile options.profile = "Custom" options.profileData = image.ProfileData.Profiles[options.profile] diff --git a/kcc/image.py b/kcc/image.py index 3101b99..009b2bb 100755 --- a/kcc/image.py +++ b/kcc/image.py @@ -78,21 +78,21 @@ class ProfileData: ] Profiles = { - 'K1': ("Kindle 1", (600, 670), Palette4, 1.8, (900, 1005)), - 'K2': ("Kindle 2", (600, 670), Palette15, 1.8, (900, 1005)), - 'K3': ("Kindle", (600, 800), Palette16, 1.8, (900, 1200)), - 'K45': ("Kindle", (600, 800), Palette16, 1.8, (900, 1200)), - 'KDX': ("Kindle DX/DXG", (824, 1000), Palette16, 1.8, (1236, 1500)), - 'KPW': ("Kindle Paperwhite 1/2", (758, 1024), Palette16, 1.8, (1137, 1536)), - 'KV': ("Kindle Paperwhite 3/Voyage/Oasis", (1072, 1448), Palette16, 1.8, (1608, 2172)), - 'KoMT': ("Kobo Mini/Touch", (600, 800), Palette16, 1.8, (900, 1200)), - 'KoG': ("Kobo Glo", (768, 1024), Palette16, 1.8, (1152, 1536)), - 'KoGHD': ("Kobo Glo HD", (1072, 1448), Palette16, 1.8, (1608, 2172)), - 'KoA': ("Kobo Aura", (758, 1024), Palette16, 1.8, (1137, 1536)), - 'KoAHD': ("Kobo Aura HD", (1080, 1440), Palette16, 1.8, (1620, 2160)), - 'KoAH2O': ("Kobo Aura H2O", (1080, 1430), Palette16, 1.8, (1620, 2145)), - 'KoAO': ("Kobo Aura ONE", (1404, 1872), Palette16, 1.8, (2106, 2808)), - 'OTHER': ("Other", (0, 0), Palette16, 1.8, (0, 0)), + 'K1': ("Kindle 1", (600, 670), Palette4, 1.8), + 'K2': ("Kindle 2", (600, 670), Palette15, 1.8), + 'K3': ("Kindle", (600, 800), Palette16, 1.8), + 'K45': ("Kindle", (600, 800), Palette16, 1.8), + 'KDX': ("Kindle DX/DXG", (824, 1000), Palette16, 1.8), + 'KPW': ("Kindle Paperwhite 1/2", (758, 1024), Palette16, 1.8), + 'KV': ("Kindle Paperwhite 3/Voyage/Oasis", (1072, 1448), Palette16, 1.8), + 'KoMT': ("Kobo Mini/Touch", (600, 800), Palette16, 1.8), + 'KoG': ("Kobo Glo", (768, 1024), Palette16, 1.8), + 'KoGHD': ("Kobo Glo HD", (1072, 1448), Palette16, 1.8), + 'KoA': ("Kobo Aura", (758, 1024), Palette16, 1.8), + 'KoAHD': ("Kobo Aura HD", (1080, 1440), Palette16, 1.8), + 'KoAH2O': ("Kobo Aura H2O", (1080, 1430), Palette16, 1.8), + 'KoAO': ("Kobo Aura ONE", (1404, 1872), Palette16, 1.8), + 'OTHER': ("Other", (0, 0), Palette16, 1.8), } @@ -106,8 +106,6 @@ class ComicPageParser: self.color = self.colorCheck() self.fill = self.fillCheck() self.splitCheck() - if self.opt.hqmode: - self.sizeCheck() def getImageHistogram(self, image): histogram = image.histogram() @@ -206,29 +204,16 @@ class ComicPageParser: else: return 'white' - def sizeCheck(self): - additionalPayload = [] - width, height = self.image.size - dstwidth, dstheight = self.size - for work in self.payload: - if width > dstwidth and height > dstheight: - additionalPayload.append([work[0] + '+', work[1], work[2].copy(), work[3], work[4]]) - self.payload = self.payload + additionalPayload - class ComicPage: def __init__(self, mode, path, image, color, fill, options): self.opt = options - _, self.size, self.palette, self.gamma, self.panelviewsize = self.opt.profileData + _, self.size, self.palette, self.gamma = self.opt.profileData self.image = image self.color = color self.fill = fill self.rotated = False self.orgPath = os.path.join(path[0], path[1]) - if '+' in mode: - self.hqMode = True - else: - self.hqMode = False if 'N' in mode: self.targetPath = os.path.join(path[0], os.path.splitext(path[1])[0]) + '-KCC' elif 'R' in mode: @@ -248,8 +233,6 @@ class ComicPage: flags.append('Rotated') if self.fill != 'white': flags.append('BlackFill') - if self.hqMode: - self.targetPath += '-HQ' if self.opt.forcepng: self.targetPath += '.png' self.image.save(self.targetPath, 'PNG', optimize=1) @@ -283,41 +266,35 @@ class ComicPage: self.image = self.image.quantize(palette=palImg) def resizeImage(self): - if self.hqMode: - size = (self.panelviewsize[0], self.panelviewsize[1]) - if self.image.size[0] > size[0] or self.image.size[1] > size[1]: - self.image.thumbnail(size, Image.LANCZOS) + if self.image.size[0] <= self.size[0] and self.image.size[1] <= self.size[1]: + method = Image.BICUBIC else: - size = (self.size[0], self.size[1]) - if self.image.size[0] <= size[0] and self.image.size[1] <= size[1]: - method = Image.BICUBIC + method = Image.LANCZOS + if self.opt.stretch: + self.image = self.image.resize(self.size, method) + elif self.image.size[0] <= self.size[0] and self.image.size[1] <= self.size[1] and not self.opt.upscale: + if self.opt.format == 'CBZ': + borderw = int((self.size[0] - self.image.size[0]) / 2) + borderh = int((self.size[1] - self.image.size[1]) / 2) + self.image = ImageOps.expand(self.image, border=(borderw, borderh), fill=self.fill) + if self.image.size[0] != self.size[0] or self.image.size[1] != self.size[1]: + self.image = ImageOps.fit(self.image, self.size, method=Image.BICUBIC, centering=(0.5, 0.5)) + else: + if self.opt.format == 'CBZ': + ratioDev = float(self.size[0]) / float(self.size[1]) + if (float(self.image.size[0]) / float(self.image.size[1])) < ratioDev: + diff = int(self.image.size[1] * ratioDev) - self.image.size[0] + self.image = ImageOps.expand(self.image, border=(int(diff / 2), 0), fill=self.fill) + elif (float(self.image.size[0]) / float(self.image.size[1])) > ratioDev: + diff = int(self.image.size[0] / ratioDev) - self.image.size[1] + self.image = ImageOps.expand(self.image, border=(0, int(diff / 2)), fill=self.fill) + self.image = ImageOps.fit(self.image, self.size, method=method, centering=(0.5, 0.5)) else: - method = Image.LANCZOS - if self.opt.stretch: - self.image = self.image.resize(size, method) - elif self.image.size[0] <= size[0] and self.image.size[1] <= size[1] and not self.opt.upscale: - if self.opt.format == 'CBZ': - borderw = int((size[0] - self.image.size[0]) / 2) - borderh = int((size[1] - self.image.size[1]) / 2) - self.image = ImageOps.expand(self.image, border=(borderw, borderh), fill=self.fill) - 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)) - else: - if self.opt.format == 'CBZ': - ratioDev = float(size[0]) / float(size[1]) - if (float(self.image.size[0]) / float(self.image.size[1])) < ratioDev: - diff = int(self.image.size[1] * ratioDev) - self.image.size[0] - self.image = ImageOps.expand(self.image, border=(int(diff / 2), 0), fill=self.fill) - elif (float(self.image.size[0]) / float(self.image.size[1])) > ratioDev: - diff = int(self.image.size[0] / ratioDev) - self.image.size[1] - self.image = ImageOps.expand(self.image, border=(0, int(diff / 2)), fill=self.fill) - self.image = ImageOps.fit(self.image, size, method=method, centering=(0.5, 0.5)) - else: - hpercent = size[1] / float(self.image.size[1]) - wsize = int((float(self.image.size[0]) * float(hpercent))) - self.image = self.image.resize((wsize, size[1]), method) - if self.image.size[0] > size[0] or self.image.size[1] > size[1]: - self.image.thumbnail(size, Image.LANCZOS) + hpercent = self.size[1] / float(self.image.size[1]) + wsize = int((float(self.image.size[0]) * float(hpercent))) + self.image = self.image.resize((wsize, self.size[1]), method) + if self.image.size[0] > self.size[0] or self.image.size[1] > self.size[1]: + self.image.thumbnail(self.size, Image.LANCZOS) def getBoundingBox(self, tmpImg): min_margin = [int(0.005 * i + 0.5) for i in tmpImg.size] From aa00ea3aa2757fa0532d85f59995a7eb00b7df9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Jastrz=C4=99bski?= Date: Mon, 21 Nov 2016 15:59:14 +0100 Subject: [PATCH 5/8] Expanded autoscale option --- kcc/comic2ebook.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/kcc/comic2ebook.py b/kcc/comic2ebook.py index 175d576..5f76d2d 100755 --- a/kcc/comic2ebook.py +++ b/kcc/comic2ebook.py @@ -80,9 +80,6 @@ def main(argv=None): makeBook(source) return 0 -def calculateZoomImageSize(imageSize, deviceRes): - scale = float(deviceRes[0])/float(imageSize[0]) - return (float(deviceRes[0]), scale * imageSize[1]) def buildHTML(path, imgfile, imgfilepath): imgfilepath = md5Checksum(imgfilepath) @@ -124,14 +121,15 @@ def buildHTML(path, imgfile, imgfilepath): "url('", "../" * backref, "Images/", postfix, imgfile, "'); " + additionalStyle + "\">\n"]) if options.iskindle and options.panelview: sizeTmp = Image.open(os.path.join(head, "Images", postfix, imgfile)).size - size = (int(sizeTmp[0] * 1.5), int(sizeTmp[1] * 1.5)) if options.autoscale: - size = calculateZoomImageSize(sizeTmp, deviceres) - if size[0] <= deviceres[0]: + size = (getPanelViewResolution(sizeTmp, deviceres)) + else: + size = (int(sizeTmp[0] * 1.5), int(sizeTmp[1] * 1.5)) + if size[0] - deviceres[0] < deviceres[0] * 0.01: noHorizontalPV = True else: noHorizontalPV = False - if size[1] <= deviceres[1]: + if size[1] - deviceres[1] < deviceres[1] * 0.01: noVerticalPV = True else: noVerticalPV = False @@ -674,6 +672,11 @@ def getDirectorySize(start_path='.'): return total_size +def getPanelViewResolution(imageSize, deviceRes): + scale = float(deviceRes[0]) / float(imageSize[0]) + return int(deviceRes[0]), int(scale * imageSize[1]) + + def getPanelViewSize(deviceres, size): x = int(deviceres[0] / 2 - size[0] / 2) / deviceres[0] * 100 y = int(deviceres[1] / 2 - size[1] / 2) / deviceres[1] * 100 @@ -931,11 +934,10 @@ def makeParser(): mainOptions.add_option("-p", "--profile", action="store", dest="profile", default="KV", help="Device profile (Available options: K1, K2, K3, K45, KDX, KPW, KV, KoMT, KoG, KoGHD," " KoA, KoAHD, KoAH2O, KoAO) [Default=KV]") - mainOptions.add_option("-a", "--auto-scale", action="store_true", dest="autoscale", default=False, - help="Auto scale image in panel view by width. The zoom-in mode will have two view ports" - "(top and bottom)") 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("-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"), From c68c9892e42ce110acec49d6e0d210b8a3e066bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Jastrz=C4=99bski?= Date: Mon, 21 Nov 2016 16:27:29 +0100 Subject: [PATCH 6/8] GUI update --- gui/KCC.ui | 4 ++-- kcc/KCC_gui.py | 46 +++++++++++++++++++++++----------------------- kcc/KCC_ui.py | 4 ++-- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/gui/KCC.ui b/gui/KCC.ui index eb8b84e..3bdd917 100644 --- a/gui/KCC.ui +++ b/gui/KCC.ui @@ -174,10 +174,10 @@ - <html><head/><body><p style='white-space:pre'>High quality Panel View.<br/>Require source files with bigger resolution than target device.<br/><span style=" font-weight:600;">Highly impact size of output file!</span></p></body></html> + <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> - HQ zoom + Panel View 4/2 diff --git a/kcc/KCC_gui.py b/kcc/KCC_gui.py index 22052bb..3ebcca5 100644 --- a/kcc/KCC_gui.py +++ b/kcc/KCC_gui.py @@ -257,7 +257,7 @@ class WorkerThread(QtCore.QThread): elif GUI.rotateBox.checkState() == 2: options.splitter = 1 if GUI.qualityBox.isChecked(): - options.hqmode = True + options.autoscale = True if GUI.webtoonBox.isChecked(): options.webtoon = True if GUI.upscaleBox.checkState() == 1: @@ -393,7 +393,7 @@ class WorkerThread(QtCore.QThread): for item in outputPath: comic2ebook.options.covers[outputPath.index(item)][0].saveToKindle( k, comic2ebook.options.covers[outputPath.index(item)][1]) - MW.addMessage.emit('Kindle detected. Uploading covers...', 'info', False) + MW.addMessage.emit('Kindle detected. Uploading covers... Done!', 'info', False) else: GUI.progress.content = '' for item in outputPath: @@ -604,7 +604,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow): GUI.upscaleBox.setChecked(True) else: profile = GUI.profiles[str(GUI.deviceBox.currentText())] - if profile['Quality']: + if profile['PVOptions']: GUI.qualityBox.setEnabled(True) GUI.mangaBox.setEnabled(True) GUI.rotateBox.setEnabled(True) @@ -631,9 +631,9 @@ class KCCGUI(KCC_ui.Ui_mainWindow): self.changeFormat() GUI.gammaSlider.setValue(0) self.changeGamma(0) - GUI.qualityBox.setEnabled(profile['Quality']) + GUI.qualityBox.setEnabled(profile['PVOptions']) GUI.upscaleBox.setChecked(profile['DefaultUpscale']) - if not profile['Quality']: + if not profile['PVOptions']: GUI.qualityBox.setChecked(False) if str(GUI.deviceBox.currentText()) == 'Other': self.addMessage('' @@ -645,7 +645,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow): GUI.formatBox.setCurrentIndex(outputFormat) else: GUI.formatBox.setCurrentIndex(profile['DefaultFormat']) - GUI.qualityBox.setEnabled(profile['Quality']) + GUI.qualityBox.setEnabled(profile['PVOptions']) def stripTags(self, html): s = HTMLStripper() @@ -896,39 +896,39 @@ class KCCGUI(KCC_ui.Ui_mainWindow): MW.resize(500, 500) self.profiles = { - "Kindle Oasis": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0, + "Kindle Oasis": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': True, 'Label': 'KV'}, - "Kindle Voyage": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0, + "Kindle Voyage": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': True, 'Label': 'KV'}, - "Kindle PW 3": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0, + "Kindle PW 3": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': True, 'Label': 'KV'}, - "Kindle PW 1/2": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0, + "Kindle PW 1/2": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': False, 'Label': 'KPW'}, - "Kindle": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0, + "Kindle": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': False, 'Label': 'K45'}, - "Kindle DX/DXG": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 2, + "Kindle DX/DXG": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 2, 'DefaultUpscale': False, 'Label': 'KDX'}, - "Kobo Mini/Touch": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 1, + "Kobo Mini/Touch": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': False, 'Label': 'KoMT'}, - "Kobo Glo": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 1, + "Kobo Glo": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': False, 'Label': 'KoG'}, - "Kobo Glo HD": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 1, + "Kobo Glo HD": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': False, 'Label': 'KoGHD'}, - "Kobo Aura": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 1, + "Kobo Aura": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': False, 'Label': 'KoA'}, - "Kobo Aura HD": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 1, + "Kobo Aura HD": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True, 'Label': 'KoAHD'}, - "Kobo Aura H2O": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 1, + "Kobo Aura H2O": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True, 'Label': 'KoAH2O'}, - "Kobo Aura ONE": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 1, + "Kobo Aura ONE": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True, 'Label': 'KoAO'}, - "Other": {'Quality': False, 'ForceExpert': True, 'DefaultFormat': 1, + "Other": {'PVOptions': False, 'ForceExpert': True, 'DefaultFormat': 1, 'DefaultUpscale': False, 'Label': 'OTHER'}, - "Kindle 1": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 0, + "Kindle 1": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': False, 'Label': 'K1'}, - "Kindle 2": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 0, + "Kindle 2": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': False, 'Label': 'K2'}, - "Kindle 3": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 0, + "Kindle 3": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': False, 'Label': 'K3'}, } profilesGUI = [ diff --git a/kcc/KCC_ui.py b/kcc/KCC_ui.py index 5418e3e..5e718ef 100644 --- a/kcc/KCC_ui.py +++ b/kcc/KCC_ui.py @@ -241,8 +241,8 @@ class Ui_mainWindow(object): self.mangaBox.setText(_translate("mainWindow", "Manga mode")) self.rotateBox.setToolTip(_translate("mainWindow", "

Unchecked - Split
Double page spreads will be cut into two separate pages.

Indeterminate - Rotate and split
Double page spreads will be displayed twice. First rotated and then split.

Checked - Rotate
Double page spreads will be rotated.

")) self.rotateBox.setText(_translate("mainWindow", "Spread splitter")) - self.qualityBox.setToolTip(_translate("mainWindow", "

High quality Panel View.
Require source files with bigger resolution than target device.
Highly impact size of output file!

")) - self.qualityBox.setText(_translate("mainWindow", "HQ zoom")) + self.qualityBox.setToolTip(_translate("mainWindow", "

Unchecked - 4 panels
Zoom each corner separately.

Checked - 2 panels
Zoom only the top and bottom of the page.

")) + self.qualityBox.setText(_translate("mainWindow", "Panel View 4/2")) self.webtoonBox.setToolTip(_translate("mainWindow", "

Enable special parsing mode for Korean Webtoons.

")) self.webtoonBox.setText(_translate("mainWindow", "Webtoon mode")) self.upscaleBox.setToolTip(_translate("mainWindow", "

Unchecked - Nothing
Images smaller than device resolution will not be resized.

Indeterminate - Stretching
Images smaller than device resolution will be resized. Aspect ratio will be not preserved.

Checked - Upscaling
Images smaller than device resolution will be resized. Aspect ratio will be preserved.

")) From 284c57789418f4d661c2ae2f8d646d0dad48a8c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Jastrz=C4=99bski?= Date: Mon, 21 Nov 2016 17:24:58 +0100 Subject: [PATCH 7/8] Fixed some file lock anomalies --- kcc/KCC_gui.py | 18 +++++++++--------- kcc/cbxarchive.py | 6 +++--- kcc/comic2ebook.py | 8 ++++---- kcc/comic2panel.py | 8 ++++---- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/kcc/KCC_gui.py b/kcc/KCC_gui.py index 3ebcca5..dcc9e1b 100644 --- a/kcc/KCC_gui.py +++ b/kcc/KCC_gui.py @@ -33,7 +33,7 @@ from distutils.version import StrictVersion from xml.sax.saxutils import escape from platform import platform from raven import Client -from .shared import md5Checksum, HTMLStripper, sanitizeTrace +from .shared import md5Checksum, HTMLStripper, sanitizeTrace, saferRemove from . import __version__ from . import comic2ebook from . import metadata @@ -331,7 +331,7 @@ class WorkerThread(QtCore.QThread): if 'outputPath' in locals(): for item in outputPath: if os.path.exists(item): - os.remove(item) + saferRemove(item) self.clean() return if not self.errors: @@ -358,9 +358,9 @@ class WorkerThread(QtCore.QThread): if not self.conversionAlive: for item in outputPath: if os.path.exists(item): - os.remove(item) + saferRemove(item) if os.path.exists(item.replace('.epub', '.mobi')): - os.remove(item.replace('.epub', '.mobi')) + saferRemove(item.replace('.epub', '.mobi')) self.clean() return if self.kindlegenErrorCode[0] == 0: @@ -381,7 +381,7 @@ class WorkerThread(QtCore.QThread): for item in outputPath: GUI.progress.content = '' mobiPath = item.replace('.epub', '.mobi') - os.remove(mobiPath + '_toclean') + saferRemove(mobiPath + '_toclean') if GUI.targetDirectory and GUI.targetDirectory != os.path.dirname(mobiPath): try: move(mobiPath, GUI.targetDirectory) @@ -399,9 +399,9 @@ class WorkerThread(QtCore.QThread): for item in outputPath: mobiPath = item.replace('.epub', '.mobi') if os.path.exists(mobiPath): - os.remove(mobiPath) + saferRemove(mobiPath) if os.path.exists(mobiPath + '_toclean'): - os.remove(mobiPath + '_toclean') + saferRemove(mobiPath + '_toclean') MW.addMessage.emit('Failed to process MOBI file!', 'error', False) MW.addTrayMessage.emit('Failed to process MOBI file!', 'Critical') else: @@ -409,9 +409,9 @@ class WorkerThread(QtCore.QThread): epubSize = (os.path.getsize(self.kindlegenErrorCode[2])) // 1024 // 1024 for item in outputPath: if os.path.exists(item): - os.remove(item) + saferRemove(item) if os.path.exists(item.replace('.epub', '.mobi')): - os.remove(item.replace('.epub', '.mobi')) + saferRemove(item.replace('.epub', '.mobi')) MW.addMessage.emit('KindleGen failed to create MOBI!', 'error', False) MW.addTrayMessage.emit('KindleGen failed to create MOBI!', 'Critical') if self.kindlegenErrorCode[0] == 1 and self.kindlegenErrorCode[1] != '': diff --git a/kcc/cbxarchive.py b/kcc/cbxarchive.py index 569dad5..3c857e7 100644 --- a/kcc/cbxarchive.py +++ b/kcc/cbxarchive.py @@ -27,7 +27,7 @@ try: except ImportError: walk = os.walk from . import rarfile -from .shared import check7ZFile as is_7zfile, saferReplace +from .shared import check7ZFile as is_7zfile, saferReplace, saferRemove class CBxArchive: @@ -66,7 +66,7 @@ class CBxArchive: for root, dirnames, filenames in walk(targetdir): for filename in filenames: if filename.startswith('__MACOSX') or filename.endswith('.DS_Store') or filename.endswith('humbs.db'): - os.remove(os.path.join(root, filename)) + saferRemove(os.path.join(root, filename)) def extractCB7(self, targetdir): # Workaround for some wide UTF-8 + Popen abnormalities @@ -80,7 +80,7 @@ class CBxArchive: if b"Everything is Ok" in line: extracted = True if sys.platform.startswith('darwin'): - os.remove(self.origFileName) + saferRemove(self.origFileName) if not extracted: raise OSError diff --git a/kcc/comic2ebook.py b/kcc/comic2ebook.py index 5f76d2d..da9c906 100755 --- a/kcc/comic2ebook.py +++ b/kcc/comic2ebook.py @@ -621,7 +621,7 @@ def getComicInfo(path, originalPath): try: xml = metadata.MetadataParser(xmlPath) except Exception: - os.remove(xmlPath) + saferRemove(xmlPath) return options.authors = [] if defaultTitle: @@ -646,7 +646,7 @@ def getComicInfo(path, originalPath): options.chapters = xml.data['Bookmarks'] if xml.data['Summary']: options.summary = escape(xml.data['Summary']) - os.remove(xmlPath) + saferRemove(xmlPath) def getCoversFromMCB(mangaID): @@ -1168,14 +1168,14 @@ def makeBook(source, qtGUI=None): print('Error: Failed to tweak KindleGen output!') return filepath else: - os.remove(i.replace('.epub', '.mobi') + '_toclean') + saferRemove(i.replace('.epub', '.mobi') + '_toclean') if k.path and k.coverSupport: options.covers[filepath.index(i)][0].saveToKindle(k, options.covers[filepath.index(i)][1]) return filepath def makeMOBIFix(item, uuid): - os.remove(item) + saferRemove(item) mobiPath = item.replace('.epub', '.mobi') move(mobiPath, mobiPath + '_toclean') try: diff --git a/kcc/comic2panel.py b/kcc/comic2panel.py index 6602a91..def8250 100644 --- a/kcc/comic2panel.py +++ b/kcc/comic2panel.py @@ -24,7 +24,7 @@ from shutil import rmtree, copytree, move from optparse import OptionParser, OptionGroup from multiprocessing import Pool from PIL import Image, ImageStat, ImageOps -from .shared import getImageFileName, walkLevel, walkSort +from .shared import getImageFileName, walkLevel, walkSort, saferRemove try: from PyQt5 import QtCore except ImportError: @@ -77,7 +77,7 @@ def mergeDirectory(work): img = ImageOps.fit(img, (targetWidth, img.size[1]), method=Image.BICUBIC, centering=(0.5, 0.5)) result.paste(img, (0, y)) y += img.size[1] - os.remove(i) + saferRemove(i) savePath = os.path.split(imagesValid[0]) result.save(os.path.join(savePath[0], os.path.splitext(savePath[1])[0] + '.png'), 'PNG') except Exception: @@ -203,7 +203,7 @@ def splitImage(work): targetHeight += panels[panel][2] newPage.save(os.path.join(path, fileExpanded[0] + '-' + str(pageNumber) + '.png'), 'PNG') pageNumber += 1 - os.remove(filePath) + saferRemove(filePath) except Exception: return str(sys.exc_info()[1]) @@ -275,7 +275,7 @@ def main(argv=None, qtGUI=None): pagenumber += 1 work.append([root, name, options]) else: - os.remove(os.path.join(root, name)) + saferRemove(os.path.join(root, name)) if GUI: GUI.progressBarTick.emit('Splitting images') GUI.progressBarTick.emit(str(pagenumber)) From 64fb4a9eca6879cb19ffa15f231221cc1b0e62e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Jastrz=C4=99bski?= Date: Tue, 22 Nov 2016 08:33:02 +0100 Subject: [PATCH 8/8] Updated README + version bump --- README.md | 35 +++++++++++++++++++++-------------- kcc.iss | 2 +- kcc/__init__.py | 2 +- other/osx/Info.plist | 6 +++--- 4 files changed, 26 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index f700680..cfaf214 100644 --- a/README.md +++ b/README.md @@ -75,9 +75,11 @@ Usage: kcc-c2e [options] comic_file|comic_folder Options: MAIN: -p PROFILE, --profile=PROFILE - Device profile (Available options: K1, K2, K3, K45, KDX, - KPW, KV, KoMT, KoG, KoGHD, KoA, KoAHD, KoAH2O, KoAO) [Default=KV] + Device profile (Available options: K1, K2, K3, K45, + KDX, KPW, KV, KoMT, KoG, KoGHD, KoA, KoAHD, KoAH2O, + KoAO) [Default=KV] -m, --manga-style Manga style (right-to-left reading and splitting) + -2, --two-panel Display two not four panels in Panel View mode -w, --webtoon Webtoon processing mode OUTPUT SETTINGS: @@ -86,29 +88,28 @@ Options: -t TITLE, --title=TITLE Comic title [Default=filename or directory name] -f FORMAT, --format=FORMAT - Output format (Available options: Auto, MOBI, EPUB, CBZ) - [Default=Auto] + Output format (Available options: Auto, MOBI, EPUB, + CBZ) [Default=Auto] -b, --batchsplit Split output into multiple files PROCESSING: -u, --upscale Resize images smaller than device's resolution -s, --stretch Stretch images to device's resolution -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 + [Default=0] -g GAMMA, --gamma=GAMMA - Apply gamma correction to linearize the image [Default=Auto] - --hq Enable high quality Panel View + Apply gamma correction to linearize the image + [Default=Auto] + -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] --blackborders Disable autodetection and force black borders --whiteborders Disable autodetection and force white borders --forcecolor Don't convert images to grayscale --forcepng Create PNG files instead JPEG - --cropping=CROPPING - Set cropping mode. 0: Disabled 1: Margins 2: Margins + - page numbers [Default=2] - --croppingpower=CROPPINGP - Set margin cropping threshold [Default=0.1] - --croppingpowerpage=CROPPINGPN - Set page number cropping threshold [Default=5.0] CUSTOM PROFILE: --customwidth=CUSTOMWIDTH @@ -159,6 +160,12 @@ The app relies and includes the following scripts: * [Kobo Aura ONE](http://kcc.iosphe.re/Samples/Ubunchu-KoAO.kepub.epub) ## CHANGELOG +####5.2: +* Added new Panel View options +* Implemented new margin detection algorithm +* Removed HQ Panel View mode +* Fixed multiple smaller issues + ####5.1.3: * Added Kobo Aura ONE profile * Fixed few small bugs diff --git a/kcc.iss b/kcc.iss index d536ab2..28a7317 100644 --- a/kcc.iss +++ b/kcc.iss @@ -1,5 +1,5 @@ #define MyAppName "Kindle Comic Converter" -#define MyAppVersion "5.1.3" +#define MyAppVersion "5.2" #define MyAppPublisher "Ciro Mattia Gonano, Paweł Jastrzębski" #define MyAppURL "http://kcc.iosphe.re/" #define MyAppExeName "KCC.exe" diff --git a/kcc/__init__.py b/kcc/__init__.py index 5382553..d4f4bd0 100644 --- a/kcc/__init__.py +++ b/kcc/__init__.py @@ -1,4 +1,4 @@ -__version__ = '5.1.3' +__version__ = '5.2' __license__ = 'ISC' __copyright__ = '2012-2016, Ciro Mattia Gonano , Pawel Jastrzebski ' __docformat__ = 'restructuredtext en' diff --git a/other/osx/Info.plist b/other/osx/Info.plist index 0194378..d883b4d 100644 --- a/other/osx/Info.plist +++ b/other/osx/Info.plist @@ -9,7 +9,7 @@ CFBundleExecutable MacOS/Kindle Comic Converter CFBundleGetInfoString - KindleComicConverter 5.1.3, written 2012-2016 by Ciro Mattia Gonano and Pawel Jastrzebski + KindleComicConverter 5.2, written 2012-2016 by Ciro Mattia Gonano and Pawel Jastrzebski CFBundleIconFile comic2ebook.icns CFBundleIdentifier @@ -21,11 +21,11 @@ CFBundlePackageType APPL CFBundleShortVersionString - 5.1.3 + 5.2.0 CFBundleSignature ???? CFBundleVersion - 5.1.3 + 5.2.0 LSEnvironment PATH