From 32a0038c4945ad40e8f7f535fe1a87eebbf24192 Mon Sep 17 00:00:00 2001 From: Ciro Mattia Gonano Date: Fri, 1 Mar 2013 16:22:11 +0100 Subject: [PATCH] Mainly adhere to PEP 8 code style (http://www.python.org/dev/peps/pep-0008/) Add some commented code for working on Panel view enhancement and natural sorting. --- kcc/cbxarchive.py | 29 ++++----- kcc/gui.py | 91 ++++++++++++++------------- kcc/image.py | 154 ++++++++++++++++++++++++---------------------- 3 files changed, 142 insertions(+), 132 deletions(-) diff --git a/kcc/cbxarchive.py b/kcc/cbxarchive.py index 54d16b3..7720d4c 100644 --- a/kcc/cbxarchive.py +++ b/kcc/cbxarchive.py @@ -14,22 +14,23 @@ # TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. # -__license__ = 'ISC' +__license__ = 'ISC' __copyright__ = '2012-2013, Ciro Mattia Gonano ' __docformat__ = 'restructuredtext en' import os + class CBxArchive: def __init__(self, origFileName): - self.cbxexts = ['.zip','.cbz','.rar','.cbr'] + self.cbxexts = ['.zip', '.cbz', '.rar', '.cbr'] self.origFileName = origFileName self.filename = os.path.splitext(origFileName) def isCbxFile(self): return self.filename[1].lower() in self.cbxexts - def extractCBZ(self,targetdir): + def extractCBZ(self, targetdir): try: from zipfile import ZipFile except ImportError: @@ -40,13 +41,13 @@ class CBxArchive: pass # skip MacOS special files elif f.endswith('/'): try: - os.makedirs(os.path.join(targetdir,f)) + os.makedirs(os.path.join(targetdir, f)) except: - pass #the dir exists so we are going to extract the images only. + pass # the dir exists so we are going to extract the images only. else: cbzFile.extract(f, targetdir) - def extractCBR(self,targetdir): + def extractCBR(self, targetdir): try: import rarfile except ImportError: @@ -55,24 +56,24 @@ class CBxArchive: cbrFile = rarfile.RarFile(self.origFileName) for f in cbrFile.namelist(): if f.startswith('__MACOSX') or f.endswith('.DS_Store'): - pass # skip MacOS special files + pass # skip MacOS special files elif f.endswith('/'): try: os.makedirs(os.path.join(targetdir,f)) except: - pass #the dir exists so we are going to extract the images only. + pass # the dir exists so we are going to extract the images only. else: cbrFile.extract(f, targetdir) - def extract(self,targetdir): + def extract(self, targetdir): if '.cbr' == self.filename[1].lower() or '.rar' == self.filename[1].lower(): self.extractCBR(targetdir) elif '.cbz' == self.filename[1].lower() or '.zip' == self.filename[1].lower(): self.extractCBZ(targetdir) - dir = os.listdir(targetdir) - if len(dir) == 1 and os.path.isdir(os.path.join(targetdir,dir[0])): + adir = os.listdir(targetdir) + if len(adir) == 1 and os.path.isdir(os.path.join(targetdir, adir[0])): import shutil - for f in os.listdir(os.path.join(targetdir,dir[0])): - shutil.move(os.path.join(targetdir,dir[0],f),targetdir) - os.rmdir(os.path.join(targetdir,dir[0])) + for f in os.listdir(os.path.join(targetdir, adir[0])): + shutil.move(os.path.join(targetdir, adir[0], f), targetdir) + os.rmdir(os.path.join(targetdir, adir[0])) return targetdir diff --git a/kcc/gui.py b/kcc/gui.py index cb10e48..1df2214 100644 --- a/kcc/gui.py +++ b/kcc/gui.py @@ -16,16 +16,22 @@ # TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -__license__ = 'ISC' +__license__ = 'ISC' __copyright__ = '2012-2013, Ciro Mattia Gonano ' __docformat__ = 'restructuredtext en' from Tkinter import * -import tkFileDialog, tkMessageBox, ttk -import comic2ebook, kindlestrip +import tkFileDialog +import tkMessageBox +import ttk +import comic2ebook +import kindlestrip from image import ProfileData -from subprocess import call, Popen, PIPE, STDOUT -import os, shutil, stat +from subprocess import call +import os +import shutil +import stat + class MainWindow: @@ -34,9 +40,9 @@ class MainWindow: self.refresh_list() def open_files(self): - filetypes = [('all files', '.*'), ('Comic files', ('*.cbr','*.cbz','*.zip','*.rar','*.pdf'))] - f = tkFileDialog.askopenfilenames(title="Choose a file...",filetypes=filetypes) - if not isinstance(f,tuple): + filetypes = [('all files', '.*'), ('Comic files', ('*.cbr', '*.cbz', '*.zip', '*.rar', '*.pdf'))] + f = tkFileDialog.askopenfilenames(title="Choose a file...", filetypes=filetypes) + if not isinstance(f, tuple): try: import re f = re.findall('\{(.*?)\}', f) @@ -58,58 +64,58 @@ class MainWindow: def refresh_list(self): self.filelocation.config(state=NORMAL) self.filelocation.delete(0, END) - for file in self.filelist: - self.filelocation.insert(END, file) + for afile in self.filelist: + self.filelocation.insert(END, afile) self.filelocation.config(state=DISABLED) def initialize(self): self.filelocation = Listbox(self.master) - self.filelocation.grid(row=0,columnspan=4,sticky=W+E+N+S) + self.filelocation.grid(row=0, columnspan=4, sticky=W + E + N + S) self.refresh_list() self.clear_file = Button(self.master, text="Clear files", command=self.clear_files) - self.clear_file.grid(row=4,column=0,rowspan=3) + self.clear_file.grid(row=4, column=0, rowspan=3) self.open_file = Button(self.master, text="Add files...", command=self.open_files) - self.open_file.grid(row=4,column=1,rowspan=3) + self.open_file.grid(row=4, column=1, rowspan=3) self.open_folder = Button(self.master, text="Add folder...", command=self.open_folder) - self.open_folder.grid(row=4,column=2,rowspan=3) + self.open_folder.grid(row=4, column=2, rowspan=3) self.profile = StringVar() profiles = sorted(ProfileData.ProfileLabels.iterkeys()) self.profile.set(profiles[-1]) w = apply(OptionMenu, (self.master, self.profile) + tuple(profiles)) - w.grid(row=1,column=3) + w.grid(row=1, column=3) self.options = { - 'epub_only':IntVar(None,0), - 'image_preprocess':IntVar(None,1), - 'cut_page_numbers':IntVar(None,1), - 'mangastyle':IntVar(None,0), - 'image_upscale':IntVar(None,0), - 'image_stretch':IntVar(None,0), - 'black_borders':IntVar(None,0) + 'epub_only': IntVar(None, 0), + 'image_preprocess': IntVar(None, 1), + 'cut_page_numbers': IntVar(None, 1), + 'mangastyle': IntVar(None, 0), + 'image_upscale': IntVar(None, 0), + 'image_stretch': IntVar(None, 0), + 'black_borders': IntVar(None, 0) } self.optionlabels = { - 'epub_only':"Generate ePub only (does not call 'kindlegen')", - 'image_preprocess':"Apply image optimizations", - 'cut_page_numbers':"Cut page numbers", - 'mangastyle':"Split manga-style (right-to-left reading)", - 'image_upscale':"Allow image upscaling", - 'image_stretch':"Stretch images", - 'black_borders':"Use black borders" + 'epub_only': "Generate ePub only (does not call 'kindlegen')", + 'image_preprocess': "Apply image optimizations", + 'cut_page_numbers': "Cut page numbers", + 'mangastyle': "Split manga-style (right-to-left reading)", + 'image_upscale': "Allow image upscaling", + 'image_stretch': "Stretch images", + 'black_borders': "Use black borders" } for key in self.options: - aCheckButton = Checkbutton(self.master, text=self.optionlabels[key],variable=self.options[key]) - aCheckButton.grid(column=3,sticky='w') + aCheckButton = Checkbutton(self.master, text=self.optionlabels[key], variable=self.options[key]) + aCheckButton.grid(column=3, sticky='w') self.progressbar = ttk.Progressbar(orient=HORIZONTAL, length=200, mode='determinate') self.submit = Button(self.master, text="Execute!", command=self.start_conversion, fg="red") self.submit.grid(column=3) - self.progressbar.grid(column=0,columnspan=4,sticky=W+E+N+S) + self.progressbar.grid(column=0, columnspan=4, sticky=W + E + N + S) -# self.debug = Listbox(self.master) -# self.debug.grid(row=9,columnspan=4,sticky=W+E+N+S) -# self.debug.insert(END, os.environ['PATH']) + self.notelabel = Label(self.master, + text="GUI can seem frozen while converting, kindly wait until some message appears!") + self.notelabel.grid(column=0, columnspan=4, sticky=W + E + N + S) def start_conversion(self): self.progressbar.start() @@ -120,9 +126,8 @@ class MainWindow: if len(self.filelist) < 1: tkMessageBox.showwarning('No file selected', "You should really select some files to convert...") return - tkMessageBox.showinfo('Starting conversion', "KCC will now start converting files. GUI can seem frozen, kindly wait until some message appears!") profilekey = ProfileData.ProfileLabels[self.profile.get()] - argv = ["-p",profilekey] + argv = ["-p", profilekey] if self.options['image_preprocess'].get() == 0: argv.append("--no-image-processing") if self.options['cut_page_numbers'].get() == 0: @@ -138,8 +143,8 @@ class MainWindow: errors = False for entry in self.filelist: self.master.update() + subargv = list(argv) try: - subargv = list(argv) subargv.append(entry) epub_path = comic2ebook.main(subargv) except Exception, err: @@ -147,7 +152,7 @@ class MainWindow: errors = True continue if self.options['epub_only'] == 1: - continue; + continue try: retcode = call("kindlegen \"" + epub_path + "\"", shell=True) if retcode < 0: @@ -158,9 +163,9 @@ class MainWindow: tkMessageBox.showerror('Error kindlegen', "Error on file %s:\n%s" % (epub_path, e)) errors = True continue + mobifile = epub_path.replace('.epub', '.mobi') try: - mobifile = epub_path.replace('.epub','.mobi') - shutil.move(mobifile,mobifile + '_tostrip') + shutil.move(mobifile, mobifile + '_tostrip') kindlestrip.main((mobifile + '_tostrip', mobifile)) os.remove(mobifile + '_tostrip') except Exception, err: @@ -178,7 +183,7 @@ class MainWindow: "Conversion successfully done!" ) - def remove_readonly(self, fn, path, excinfo): + def remove_readonly(self, fn, path): if fn is os.rmdir: os.chmod(path, stat.S_IWRITE) os.rmdir(path) @@ -191,5 +196,3 @@ class MainWindow: self.master = master self.master.title(title) self.initialize() - - diff --git a/kcc/image.py b/kcc/image.py index 530649b..9421d15 100755 --- a/kcc/image.py +++ b/kcc/image.py @@ -15,13 +15,14 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -__license__ = 'ISC' +__license__ = 'ISC' __copyright__ = '2012-2013, Ciro Mattia Gonano ' __docformat__ = 'restructuredtext en' import os from PIL import Image, ImageOps, ImageDraw, ImageStat + class ImageFlags: Orient = 1 << 0 Resize = 1 << 1 @@ -86,17 +87,18 @@ class ProfileData: } ProfileLabels = { - "Kindle" : 'K1', - "Kindle 2" : 'K2', - "Kindle 3/Keyboard" : 'K3', - "Kindle 4/NT/Touch" : 'K4', - "Kindle Paperwhite" : 'KHD', - "Kindle DX" : 'KDX', - "Kindle DXG" : 'KDXG' + "Kindle": 'K1', + "Kindle 2": 'K2', + "Kindle 3/Keyboard": 'K3', + "Kindle 4/NT/Touch": 'K4', + "Kindle Paperwhite": 'KHD', + "Kindle DX": 'KDX', + "Kindle DXG": 'KDXG' } + class ComicPage: - def __init__(self,source,device): + def __init__(self, source, device): try: self.profile_label, self.size, self.palette = ProfileData.Profiles[device] except KeyError: @@ -108,13 +110,13 @@ class ComicPage: raise RuntimeError('Cannot read image file %s' % source) self.image = self.image.convert('RGB') - def saveToDir(self,targetdir): + def saveToDir(self, targetdir): filename = os.path.basename(self.origFileName) try: self.image = self.image.convert('L') # convert to grayscale - self.image.save(os.path.join(targetdir,filename),"JPEG") + self.image.save(os.path.join(targetdir, filename), "JPEG") except IOError as e: - raise RuntimeError('Cannot write image in directory %s: %s' %(targetdir,e)) + raise RuntimeError('Cannot write image in directory %s: %s' % (targetdir, e)) def optimizeImage(self): self.image = ImageOps.autocontrast(self.image) @@ -122,12 +124,12 @@ class ComicPage: def quantizeImage(self): colors = len(self.palette) / 3 if colors < 256: - self.palette = self.palette + self.palette[:3] * (256 - colors) + self.palette += self.palette[:3] * (256 - colors) palImg = Image.new('P', (1, 1)) palImg.putpalette(self.palette) self.image = self.image.quantize(palette=palImg) - def resizeImage(self,upscale=False, stretch=False, black_borders=False): + def resizeImage(self, upscale=False, stretch=False, black_borders=False): method = Image.ANTIALIAS if black_borders: fill = 'black' @@ -138,23 +140,23 @@ class ComicPage: # do not upscale but center image in a device-sized image borderw = (self.size[0] - self.image.size[0]) / 2 borderh = (self.size[1] - self.image.size[1]) / 2 - self.image = ImageOps.expand(self.image, border=(borderw,borderh), fill=fill) + self.image = ImageOps.expand(self.image, border=(borderw, borderh), fill=fill) return self.image else: method = Image.NEAREST - if stretch: # if stretching call directly resize() without other considerations. - self.image = self.image.resize(self.size,method) + if stretch: # if stretching call directly resize() without other considerations. + self.image = self.image.resize(self.size, method) return self.image 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=(diff/2,0), fill=fill) + self.image = ImageOps.expand(self.image, border=(diff / 2, 0), fill=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,diff/2), fill=fill) - self.image = ImageOps.fit(self.image, self.size, method = method, centering = (0.5,0.5)) + self.image = ImageOps.expand(self.image, border=(0, diff / 2), fill=fill) + self.image = ImageOps.fit(self.image, self.size, method=method, centering=(0.5, 0.5)) return self.image def splitPage(self, targetdir, righttoleft=False): @@ -165,12 +167,12 @@ class ComicPage: if (width > height) != (dstwidth > dstheight): if width > height: # source is landscape, so split by the width - leftbox = (0, 0, width/2, height) - rightbox = (width/2, 0, width, height) + leftbox = (0, 0, width / 2, height) + rightbox = (width / 2, 0, width, height) else: # source is portrait and target is landscape, so split by the height - leftbox = (0, 0, width, height/2) - rightbox = (0, height/2, width, height) + leftbox = (0, 0, width, height / 2) + rightbox = (0, height / 2, width, height) filename = os.path.splitext(os.path.basename(self.origFileName)) fileone = targetdir + '/' + filename[0] + '-1' + filename[1] filetwo = targetdir + '/' + filename[0] + '-2' + filename[1] @@ -185,8 +187,8 @@ class ComicPage: pagetwo.save(filetwo) os.remove(self.origFileName) except IOError as e: - raise RuntimeError('Cannot write image in directory %s: %s' %(targetdir,e)) - return fileone,filetwo + raise RuntimeError('Cannot write image in directory %s: %s' % (targetdir, e)) + return fileone, filetwo else: return None @@ -213,56 +215,57 @@ class ComicPage: draw.rectangle([corner1, corner2], outline=foreground) self.image = imageBg - def cutPageNumber(self): widthImg, heightImg = self.image.size delta = 2 diff = delta fixedThreshold = 5 - if ImageStat.Stat(self.image).var[0] < 2*fixedThreshold: + 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: + 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 0\ - and diff < heightImg/4: - oldStat=ImageStat.Stat(self.image.crop((0,heightImg-diff,widthImg,heightImg))).var[0] + 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: + 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: + 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: + 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 + 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)) + diff = pageNumberCut1 + self.image = self.image.crop((0, 0, widthImg, heightImg - diff)) return self.image def cropWhiteSpace(self, threshold): @@ -270,68 +273,71 @@ class ComicPage: delta = 10 diff = delta # top - while ImageStat.Stat(self.image.crop((0,0,widthImg,diff))).var[0] < threshold and diff < heightImg: + while ImageStat.Stat(self.image.crop((0, 0, widthImg, diff))).var[0] < threshold and diff < heightImg: diff += delta diff -= delta # print "Top crop: %s"%diff - self.image = self.image.crop((0,diff,widthImg,heightImg)) + 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] < threshold and diff < widthImg: + while ImageStat.Stat(self.image.crop((0, 0, diff, heightImg))).var[0] < threshold and diff < widthImg: diff += delta diff -= delta # print "Left crop: %s"%diff - self.image = self.image.crop((diff,0,widthImg,heightImg)) + 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] < threshold\ - and diff < heightImg: + while ImageStat.Stat(self.image.crop((0, heightImg - diff, widthImg, heightImg))).var[0] < threshold\ + and diff < heightImg: diff += delta diff -= delta # print "Down crop: %s"%diff - self.image = self.image.crop((0,0,widthImg,heightImg-diff)) + 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] < threshold\ - and diff < widthImg: + while ImageStat.Stat(self.image.crop((widthImg - diff, 0, widthImg, heightImg))).var[0] < threshold\ + and diff < widthImg: diff += delta diff -= delta # print "Right crop: %s"%diff - self.image = self.image.crop((0,0 ,widthImg-diff,heightImg)) + self.image = self.image.crop((0, 0, widthImg - diff, heightImg)) # print "New size: %sx%s"%(self.image.size[0],self.image.size[1]) return self.image def addProgressbar(self, file_number, files_totalnumber, size, howoften): - if file_number//howoften!=float(file_number)/howoften: + if file_number // howoften != float(file_number) / howoften: return self.image - white = (255,255,255) - black = (0,0,0) + white = (255, 255, 255) + black = (0, 0, 0) widthDev, heightDev = size widthImg, heightImg = self.image.size pastePt = ( max(0, (widthDev - widthImg) / 2), max(0, (heightDev - heightImg) / 2) - ) - imageBg = Image.new('RGB',size,white) + ) + imageBg = Image.new('RGB', size, white) imageBg.paste(self.image, pastePt) self.image = imageBg widthImg, heightImg = self.image.size draw = ImageDraw.Draw(self.image) #Black rectangle - draw.rectangle([(0,heightImg-3), (widthImg,heightImg)], outline=black, fill=black) + draw.rectangle([(0, heightImg - 3), (widthImg, heightImg)], outline=black, fill=black) #White rectangle - draw.rectangle([(widthImg*file_number/files_totalnumber,heightImg-3), (widthImg-1,heightImg)], outline=black, fill=white) + draw.rectangle([(widthImg * file_number / files_totalnumber, heightImg - 3), (widthImg - 1, heightImg)], + outline=black, fill=white) #Making notches - for i in range(1,10): - if i <= (10*file_number/files_totalnumber): - notch_colour=white #White + for i in range(1, 10): + if i <= (10 * file_number / files_totalnumber): + notch_colour = white # White else: - notch_colour=black #Black - draw.line([(widthImg*float(i)/10,heightImg-3), (widthImg*float(i)/10,heightImg)],fill=notch_colour) + notch_colour = black # Black + draw.line([(widthImg * float(i) / 10, heightImg - 3), (widthImg * float(i) / 10, heightImg)], + fill=notch_colour) #The 50% - if i==5: - draw.rectangle([(widthImg/2-1,heightImg-5), (widthImg/2+1,heightImg)],outline=black,fill=notch_colour) + if i == 5: + draw.rectangle([(widthImg / 2 - 1, heightImg - 5), (widthImg / 2 + 1, heightImg)], + outline=black, fill=notch_colour) return self.image