diff options
author | Ciro Mattia Gonano <ciromattia@gmail.com> | 2013-01-29 15:01:36 +0100 |
---|---|---|
committer | Ciro Mattia Gonano <ciromattia@gmail.com> | 2013-01-29 15:01:36 +0100 |
commit | d136f8cc3a8eeca5aa5a7f3ea642447ebbb5fa75 (patch) | |
tree | e9eab8bcb5af23eba1f5c4b891b77c9ef937daf0 | |
parent | Formatting (diff) | |
download | kcc-d136f8cc3a8eeca5aa5a7f3ea642447ebbb5fa75.tar.gz kcc-d136f8cc3a8eeca5aa5a7f3ea642447ebbb5fa75.tar.bz2 kcc-d136f8cc3a8eeca5aa5a7f3ea642447ebbb5fa75.zip |
Use temporary directory as workdir (fixes converting from external volumes and zipfiles renaming)
Fixed "add folders" from GUI.
-rw-r--r-- | README.md | 10 | ||||
-rw-r--r-- | kcc.py | 2 | ||||
-rw-r--r-- | kcc/cbxarchive.py | 46 | ||||
-rwxr-xr-x | kcc/comic2ebook.py | 74 | ||||
-rw-r--r-- | kcc/gui.py | 6 | ||||
-rwxr-xr-x | kcc/image.py | 20 |
6 files changed, 65 insertions, 93 deletions
diff --git a/README.md b/README.md index 3c94ccc..657efad 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,8 @@ It also optimizes comic images by: ## BINARY RELEASES You can find the latest released binary at the following links: -- OS X: [https://dl.dropbox.com/u/16806101/KindleComicConverter_osx_2.3.zip](https://dl.dropbox.com/u/16806101/KindleComicConverter_osx_2.3.zip) -- Win64: [https://dl.dropbox.com/u/16806101/KindleComicConverter_win-amd64_2.3.zip](https://dl.dropbox.com/u/16806101/KindleComicConverter_win-amd64_2.3.zip) +- OS X: [https://dl.dropbox.com/u/16806101/KindleComicConverter_osx_2.4.zip](https://dl.dropbox.com/u/16806101/KindleComicConverter_osx_2.4.zip) +- Win64: [https://dl.dropbox.com/u/16806101/KindleComicConverter_win-amd64_2.4.zip](https://dl.dropbox.com/u/16806101/KindleComicConverter_win-amd64_2.4.zip) - Linux: just download sourcecode and launch `python kcc.py` *(provided you have Python and Pillow installed)* ## INPUT FORMATS @@ -40,6 +40,8 @@ As of v. 1.50, KCC supports subfolders! ### GUI Should be pretty self-explanatory, just keep in mind that it's still in development ;) +While working it seems frozen, I'll try to fix the aesthetics later. +Conversion being done, you should find an .epub and a .mobi files alongside the original input file (same directory) ### Standalone `comic2ebook.py` usage: @@ -104,7 +106,9 @@ and installed in a directory reachable by your PATH (e.g. `/usr/local/bin/` or ` - 2.1: Added basic error reporting - 2.2: Added (valid!) ePub 2.0 output Rename .zip files to .cbz to avoid overwriting - - 2.3: Fixed win32 ePub generation, folder handling, filenames with spaces and subfolders. + - 2.3: Fixed win32 ePub generation, folder handling, filenames with spaces and subfolders + - 2.4: Use temporary directory as workdir (fixes converting from external volumes and zipfiles renaming) + Fixed "add folders" from GUI. ## TODO - Add gracefully exit for CBR if no rarfile.py and no unrar executable are found diff --git a/kcc.py b/kcc.py index 9986586..af0955e 100644 --- a/kcc.py +++ b/kcc.py @@ -16,7 +16,7 @@ # TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. # -__version__ = '2.3' +__version__ = '2.4' __license__ = 'ISC' __copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>' __docformat__ = 'restructuredtext en' diff --git a/kcc/cbxarchive.py b/kcc/cbxarchive.py index 6b0e7ea..54d16b3 100644 --- a/kcc/cbxarchive.py +++ b/kcc/cbxarchive.py @@ -25,35 +25,28 @@ class CBxArchive: self.cbxexts = ['.zip','.cbz','.rar','.cbr'] self.origFileName = origFileName self.filename = os.path.splitext(origFileName) - self.path = self.filename[0] def isCbxFile(self): - result = (self.filename[1].lower() in self.cbxexts) - if result == True: - return result - return False + return self.filename[1].lower() in self.cbxexts - def getPath(self): - return self.path - - def extractCBZ(self): + def extractCBZ(self,targetdir): try: from zipfile import ZipFile except ImportError: self.cbzFile = None cbzFile = ZipFile(self.origFileName) for f in cbzFile.namelist(): - if (f.startswith('__MACOSX') or f.endswith('.DS_Store')): + if f.startswith('__MACOSX') or f.endswith('.DS_Store'): pass # skip MacOS special files elif f.endswith('/'): try: - os.makedirs(self.path+'/'+f) + os.makedirs(os.path.join(targetdir,f)) except: pass #the dir exists so we are going to extract the images only. else: - cbzFile.extract(f, self.path) + cbzFile.extract(f, targetdir) - def extractCBR(self): + def extractCBR(self,targetdir): try: import rarfile except ImportError: @@ -61,24 +54,25 @@ class CBxArchive: return cbrFile = rarfile.RarFile(self.origFileName) for f in cbrFile.namelist(): - if (f.startswith('__MACOSX') or f.endswith('.DS_Store')): + if f.startswith('__MACOSX') or f.endswith('.DS_Store'): pass # skip MacOS special files elif f.endswith('/'): try: - os.makedirs(self.path+'/'+f) + os.makedirs(os.path.join(targetdir,f)) except: pass #the dir exists so we are going to extract the images only. else: - cbrFile.extract(f, self.path) + cbrFile.extract(f, targetdir) - def extract(self): - if ('.cbr' == self.filename[1].lower() or '.rar' == self.filename[1].lower()): - self.extractCBR() - elif ('.cbz' == self.filename[1].lower() or '.zip' == self.filename[1].lower()): - self.extractCBZ() - dir = os.listdir(self.path) - if (len(dir) == 1): + 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])): import shutil - for f in os.listdir(self.path + "/" + dir[0]): - shutil.move(self.path + "/" + dir[0] + "/" + f,self.path) - os.rmdir(self.path + "/" + dir[0]) + 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])) + return targetdir diff --git a/kcc/comic2ebook.py b/kcc/comic2ebook.py index bfe336e..c556512 100755 --- a/kcc/comic2ebook.py +++ b/kcc/comic2ebook.py @@ -16,39 +16,20 @@ # TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. # -# Changelog -# 1.00 - Initial version -# 1.10 - Added support for CBZ/CBR files -# 1.11 - Added support for ZIP/RAR extensions -# 1.20 - Comic optimizations! Split pages not target-oriented (landscape -# with portrait target or portrait with landscape target), add palette -# and other image optimizations from Mangle. -# WARNING: PIL is required for all image mangling! -# 1.30 - Fixed an issue in OPF generation for device resolution -# Reworked options system (call with -h option to get the inline help) -# 1.40 - Added some options for controlling image optimization -# Further optimization (ImageOps, page numbering cut, autocontrast) -# 1.41 - Fixed a serious bug on resizing when img ratio was bigger than device one -# 1.50 - Support for subfolders -# -# Todo: -# - Add gracefully exit for CBR if no rarfile.py and no unrar -# executable are found -# - Improve error reporting - -__version__ = '2.3' +__version__ = '2.4' __license__ = 'ISC' __copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>' __docformat__ = 'restructuredtext en' -import os, sys -from shutil import move,copyfile,make_archive,rmtree +import os, sys, tempfile +from shutil import move,copyfile,copytree,rmtree,make_archive from optparse import OptionParser import image, cbxarchive, pdfjpgextract def buildHTML(path,file): filename = getImageFileName(file) if filename is not None: + htmlpath = '' postfix = '' backref = 1 head = path @@ -203,9 +184,9 @@ def dirImgProcess(path): if options.verbose: print "Splitted " + file img0 = image.ComicPage(split[0],options.profile) - img1 = image.ComicPage(split[1],options.profile) applyImgOptimization(img0) img0.saveToDir(dirpath) + img1 = image.ComicPage(split[1],options.profile) applyImgOptimization(img1) img1.saveToDir(dirpath) else: @@ -238,35 +219,31 @@ def genEpubStruct(path): if cover is None: cover = os.path.join(filelist[-1][0],'cover' + getImageFileName(filelist[-1][1])[1]) copyfile(os.path.join(filelist[-1][0],filelist[-1][1]), cover) - if options.title == 'defaulttitle': - options.title = os.path.basename(path) buildNCX(path,options.title,chapterlist) # ensure we're sorting files alphabetically filelist = sorted(filelist, key=lambda name: (name[0].lower(), name[1].lower())) buildOPF(options.profile,path,options.title,filelist,cover) def getWorkFolder(file): + workdir = tempfile.mkdtemp() fname = os.path.splitext(file) - if fname[1].lower() == '.pdf': + if os.path.isdir(file): + try: + import shutil + os.rmdir(workdir) # needed for copytree() fails if dst already exists + copytree(file, workdir) + path = workdir + except OSError: + raise + elif fname[1].lower() == '.pdf': pdf = pdfjpgextract.PdfJpgExtract(file) - pdf.extract() - path = pdf.getPath() + path = pdf.extract(workdir) else: - if fname[1].lower() == '.zip': - move(file,fname[0] + '.cbz') - file = fname[0] + '.cbz' cbx = cbxarchive.CBxArchive(file) if cbx.isCbxFile(): - cbx.extract() - path = cbx.getPath() + path = cbx.extract(workdir) else: - try: - import shutil - if not os.path.isdir(file + "_orig"): - shutil.copytree(file, file + "_orig") - path = file - except OSError: - raise + raise TypeError move(path,path + "_temp") move(path + "_temp",os.path.join(path,'OEBPS','Images')) return path @@ -304,18 +281,23 @@ def main(argv=None): if len(args) != 1: parser.print_help() return - path = args[0] - path = getWorkFolder(path) + path = getWorkFolder(args[0]) + if options.title == 'defaulttitle': + options.title = os.path.splitext(os.path.basename(args[0]))[0] if options.imgproc: print "Processing images..." dirImgProcess(path + "/OEBPS/Images/") print "Creating ePub structure..." genEpubStruct(path) # actually zip the ePub - make_archive(path,'zip',path) - move(path + '.zip', path + '.epub') + if os.path.isdir(args[0]): + epubpath = args[0] + '.epub' + else: + epubpath = os.path.splitext(args[0])[0] + '.epub' + make_archive(os.path.join(path,'comic'),'zip',path) + move(os.path.join(path,'comic') + '.zip', epubpath) rmtree(path) - epub_path = path + '.epub' + return epubpath def getEpubPath(): global epub_path diff --git a/kcc/gui.py b/kcc/gui.py index 0565a0f..e0daed3 100644 --- a/kcc/gui.py +++ b/kcc/gui.py @@ -51,7 +51,8 @@ class MainWindow: self.refresh_list() def open_folder(self): - self.filelist = tkFileDialog.askdirectory(title="Choose a folder...") + f = tkFileDialog.askdirectory(title="Choose a folder...") + self.filelist.extend([f]) self.refresh_list() def refresh_list(self): @@ -146,8 +147,7 @@ class MainWindow: try: subargv = list(argv) subargv.append(entry) - comic2ebook.main(subargv) - epub_path = comic2ebook.getEpubPath() + epub_path = comic2ebook.main(subargv) except Exception, err: tkMessageBox.showerror('Error comic2ebook', "Error on file %s:\n%s" % (subargv[-1], str(err))) errors = True diff --git a/kcc/image.py b/kcc/image.py index a55db41..6dd6f9c 100755 --- a/kcc/image.py +++ b/kcc/image.py @@ -110,10 +110,9 @@ class ComicPage: def saveToDir(self,targetdir): filename = os.path.basename(self.origFileName) - #print "Saving to " + targetdir + '/' + filename try: self.image = self.image.convert('L') # convert to grayscale - self.image.save(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)) @@ -133,11 +132,9 @@ class ComicPage: if self.image.size[0] <= self.size[0] and self.image.size[1] <= self.size[1]: if not upscale: # do not upscale but center image in a device-sized image - newImage = Image.new('RGB', (self.size[0], self.size[1]), (255,255,255)) - newImage.paste(self.image, ( - (self.size[0] - self.image.size[0]) / 2, - (self.size[1] - self.image.size[1]) / 2)) - self.image = newImage + 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='white') return self.image else: method = Image.NEAREST @@ -149,14 +146,10 @@ class ComicPage: 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] - newImage = Image.new('RGB', (self.image.size[0] + diff, self.image.size[1]), (255,255,255)) - newImage.paste(self.image, (diff / 2, 0, diff / 2 + self.image.size[0], self.image.size[1])) - self.image = newImage + self.image = ImageOps.expand(self.image, border=(diff/2,0), fill='white') elif (float(self.image.size[0]) / float(self.image.size[1])) > ratioDev: diff = int(self.image.size[0] / ratioDev) - self.image.size[1] - newImage = Image.new('RGB', (self.image.size[0], self.image.size[1] + diff), (255,255,255)) - newImage.paste(self.image, (0, diff / 2, self.image.size[0], diff / 2 + self.image.size[1])) - self.image = newImage + self.image = ImageOps.expand(self.image, border=(0,diff/2), fill='white') self.image = ImageOps.fit(self.image, self.size, method = method, centering = (0.5,0.5)) return self.image @@ -338,4 +331,3 @@ class ComicPage: if i==5: draw.rectangle([(widthImg/2-1,heightImg-5), (widthImg/2+1,heightImg)],outline=black,fill=notch_colour) return self.image - |