diff --git a/README.md b/README.md index e067265..3664ee2 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# KCC +# KCC `KCC` (a.k.a. `KindleComicConverter`) is a Python app to convert comic files or folders to ePub or Panel View MOBI. It was initally developed for Kindle but since v2.2 it outputs valid ePub 2.0 so _**despite its name, KCC is @@ -16,9 +16,14 @@ _kc2_ in no way is a replacement for **KCC** so you can be quite confident we'll You can find the latest released binary at the following links: - OS X: [https://dl.dropbox.com/u/16806101/KindleComicConverter_osx_2.9.zip](https://dl.dropbox.com/u/16806101/KindleComicConverter_osx_2.9.zip) - Win64: [https://dl.dropbox.com/u/16806101/KindleComicConverter_win-amd64_2.9.zip](https://dl.dropbox.com/u/16806101/KindleComicConverter_win-amd64_2.9.zip) -- Win32: [http://pawelj.vulturis.eu/Shared/KindleComicConverter_win-x86_2.9.zip](http://pawelj.vulturis.eu/Shared/KindleComicConverter_win-x86_2.9.zip) *(thanks to [AcidWeb](https://github.com/AcidWeb))* +- Win32: [http://pawelj.vulturis.eu/Shared/KindleComicConverter_win-x86_2.9.zip](http://pawelj.vulturis.eu/Shared/KindleComicConverter_win-x86_2.9.zip) - Linux: Just download sourcecode and launch `python kcc.py` *(Provided you have Python and Pillow installed)* +## AWKCC .NET GUI +![AWKCC](http://pawelj.vulturis.eu/Shared/CurrentAWKCC.png) + +[All-in-one package for Windows users](http://www.mobileread.com/forums/showpost.php?p=2444957&postcount=3) + ## INPUT FORMATS `kcc` can understand and convert, at the moment, the following file types: - PNG, JPG, GIF, TIFF, BMP @@ -53,7 +58,7 @@ Options: --version show program's version number and exit -h, --help show this help message and exit -p PROFILE, --profile=PROFILE - Device profile (Choose one among K1, K2, K3, K4NT, K4T, KDX, KDXG or KHD) [Default=KHD] + Device profile (Choose one among K1, K2, K3, K4NT, K4T, KDX, KDXG, KHD, KF, KFHD, KFHD8) [Default=KHD] -t TITLE, --title=TITLE Comic title [Default=filename] -m, --manga-style Manga style (Right-to-left reading and splitting) [Default=False] @@ -88,55 +93,92 @@ The app relies and includes the following scripts/binaries: - `magic.py` from [python-magic](https://github.com/ahupp/python-magic) library ## CHANGELOG - - 1.00: Initial version - - 1.10: Added support for CBZ/CBR files in comic2ebook.py - - 1.11: Added support for CBZ/CBR files in KindleComicConverter - - 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: Added subfolder support for multiple chapters. - - 2.0: GUI! AppleScript is gone and Tk is used to provide cross-platform GUI support. - - 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.4: Use temporary directory as workdir (fixes converting from external volumes and zipfiles renaming) - Fixed "add folders" from GUI. - - 2.5: Added --black-borders option to set added borders black when page's ratio is not the device's one (#11). - Fixes epub containing zipped itself (#10) - - 2.6: Added --rotate option to rotate landscape images instead of splitting them (#16, #24) - Added --output option to customize ePub output dir/file (#22) - Add rendition:layout and rendition:orientation ePub meta tags (supported by new kindlegen 2.8) - Fixed natural sorting for files (#18) - - 2.7: Lots of GUI improvements (#27, #13) - Added gamma support within --gamma option (defaults to profile-specified gamma) (#26, #27) - Added --nodithering option to prevent dithering optimizations (#27) - Epub margins support (#30) - Fixed no file added if file has no spaces on Windows (#25) - Gracefully exit if unrar missing (#15) - Do not call kindlegen if source epub is bigger than 320MB (#17) - Get filetype from magic number (#14) - PDF conversion works again - - 2.8: updated rarfile library - Panel View support + HQ support (#36) - new option: --nopanelviewhq - Split profiles for K4NT and K4T - Rewrite of Landscape Mode support (huge readability improvement for KPW) - Upscale use now BILINEAR method - Added generic CSS file - Optimized archive extraction for zip/rar files (#40) - - 2.9: Added support for generating a plain CBZ (skipping all the EPUB/Mobi generation) (#45) - Prevent output file overwriting the source one: if a duplicate name is detected, append _kcc to the name - Rarfile library updated to 2.6 - Added GIF, TIFF and BMP to supported formats (#42) - Filenames slugifications (#28, #31, #9, #8) - - 2.10: Kindle Fire support (color ePub/Mobi) - Panel View support for horizontal content +####1.00 +* Initial version +####1.10 +* Added support for CBZ/CBR files in comic2ebook.py + +####1.11 +* Added support for CBZ/CBR files in KindleComicConverter + +####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 +* Added subfolder support for multiple chapters. + +####2.0 +* GUI! AppleScript is gone and Tk is used to provide cross-platform GUI support. + +####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.4 +* Use temporary directory as workdir (fixes converting from external volumes and zipfiles renaming) +* Fixed "add folders" from GUI. + +####2.5 +* Added --black-borders option to set added borders black when page's ratio is not the device's one (#11). +* Fixes epub containing zipped itself (#10) + +####2.6 +* Added --rotate option to rotate landscape images instead of splitting them (#16, #24) +* Added --output option to customize ePub output dir/file (#22) +* Add rendition:layout and rendition:orientation ePub meta tags (supported by new kindlegen 2.8) +* Fixed natural sorting for files (#18) + +####2.7 +* Lots of GUI improvements (#27, #13) +* Added gamma support within --gamma option (defaults to profile-specified gamma) (#26, #27) +* Added --nodithering option to prevent dithering optimizations (#27) +* Epub margins support (#30) +* Fixed no file added if file has no spaces on Windows (#25) +* Gracefully exit if unrar missing (#15) +* Do not call kindlegen if source epub is bigger than 320MB (#17) +* Get filetype from magic number (#14) +* PDF conversion works again + +####2.8 +* Updated rarfile library +* Panel View support + HQ support (#36) - new option: --nopanelviewhq +* Split profiles for K4NT and K4T +* Rewrite of Landscape Mode support (huge readability improvement for KPW) +* Upscale use now BILINEAR method +* Added generic CSS file +* Optimized archive extraction for zip/rar files (#40) + +####2.9 +* Added support for generating a plain CBZ (skipping all the EPUB/Mobi generation) (#45) +* Prevent output file overwriting the source one: if a duplicate name is detected, append _kcc to the name +* Rarfile library updated to 2.6 +* Added GIF, TIFF and BMP to supported formats (#42) +* Filenames slugifications (#28, #31, #9, #8) + +####2.10: +* Multiprocessing support +* Kindle Fire support (color ePub/Mobi) +* Panel View support for horizontal content +* Fixed panel order for horizontal pages when --rotate is enabled +* Disabled cropping and page number cutting for blank pages ## COPYRIGHT diff --git a/kcc/comic2ebook.py b/kcc/comic2ebook.py index b92ed22..4db695d 100755 --- a/kcc/comic2ebook.py +++ b/kcc/comic2ebook.py @@ -32,6 +32,7 @@ from shutil import copytree from shutil import rmtree from shutil import make_archive from optparse import OptionParser +from multiprocessing import Pool import image import cbxarchive import pdfjpgextract @@ -40,6 +41,11 @@ import pdfjpgextract def buildHTML(path, imgfile): filename = getImageFileName(imgfile) if filename is not None: + # All files marked with this sufix need horizontal Panel View. + if "_rotated" in str(filename): + rotate = True + else: + rotate = False htmlpath = '' postfix = '' backref = 1 @@ -70,7 +76,7 @@ def buildHTML(path, imgfile): imgfile, "\" class=\"singlePage\"/>\n" ]) if options.panelview: - if options.panelviewhorizontal: + if rotate: if options.righttoleft: f.writelines(["
\n", @@ -250,7 +256,7 @@ def buildOPF(profile, dstdir, title, filelist, cover=None): f.write("\n\n") splitCountUsed = 1 for entry in reflist: - if entry.endswith("-1"): + if entry.endswith("-000001") or entry.endswith("-1"): # noinspection PyRedundantParentheses if ((options.righttoleft and facing == 'left') or (not options.righttoleft and facing == 'right')) and\ options.landscapemode: @@ -260,7 +266,7 @@ def buildOPF(profile, dstdir, title, filelist, cover=None): f.write("\n") else: f.write("\n") - elif entry.endswith("-2"): + elif entry.endswith("-000002") or entry.endswith("-2"): if options.landscapemode: f.write("\n") else: @@ -309,16 +315,7 @@ def getImageFileName(imgfile): return filename -def isInFilelist(filename, filelist): - filename = os.path.splitext(filename) - seen = False - for item in filelist: - if filename[0] == item[0]: - seen = True - return seen - - -def applyImgOptimization(img, isSplit=False, toRight=False): +def applyImgOptimization(img, isSplit, toRight, options): img.cropWhiteSpace(10.0) if options.cutpagenumbers: img.cutPageNumber() @@ -331,51 +328,62 @@ def applyImgOptimization(img, isSplit=False, toRight=False): def dirImgProcess(path): global options, splitCount - if options.righttoleft: - facing = "right" - else: - facing = "left" - + work = [] + pagenumber = 0 + pagenumbermodifier = 0 + pool = Pool() for (dirpath, dirnames, filenames) in os.walk(path): for afile in filenames: if getImageFileName(afile) is not None: - if options.verbose: - print "Optimizing " + afile + " for " + options.profile - else: - print ".", - img = image.ComicPage(os.path.join(dirpath, afile), options.profile) - if options.nosplitrotate: - split = None - else: - split = img.splitPage(dirpath, options.righttoleft, options.rotate) - if split is not None: - if options.verbose: - print "Splitted " + afile - if options.righttoleft: - toRight1 = False - toRight2 = True - if facing == "left": - splitCount += 1 - facing = "right" - else: - toRight1 = True - toRight2 = False - if facing == "right": - splitCount += 1 - facing = "left" - img0 = image.ComicPage(split[0], options.profile) - applyImgOptimization(img0, True, toRight1) - img0.saveToDir(dirpath, options.forcepng, options.forcecolor) - img1 = image.ComicPage(split[1], options.profile) - applyImgOptimization(img1, True, toRight2) - img1.saveToDir(dirpath, options.forcepng, options.forcecolor) - else: - if facing == "right": - facing = "left" - else: - facing = "right" - applyImgOptimization(img) - img.saveToDir(dirpath, options.forcepng, options.forcecolor) + pagenumber += 1 + work.append([afile, dirpath, pagenumber, options]) + splitpages = pool.map(fileImgProcess, work) + pool.close() + pool.join() + splitpages = filter(None, splitpages) + splitpages.sort() + for page in splitpages: + if (page + pagenumbermodifier) % 2 == 0: + splitCount += 1 + pagenumbermodifier += 1 + pagenumbermodifier += 1 + + +def fileImgProcess(work): + afile = work[0] + dirpath = work[1] + pagenumber = work[2] + options = work[3] + output = None + if options.verbose: + print "Optimizing " + afile + " for " + options.profile + else: + print ".", + img = image.ComicPage(os.path.join(dirpath, afile), options.profile) + if options.nosplitrotate: + split = None + else: + split = img.splitPage(dirpath, options.righttoleft, options.rotate) + if split is not None and split is not "R": + if options.verbose: + print "Splitted " + afile + if options.righttoleft: + toRight1 = False + toRight2 = True + else: + toRight1 = True + toRight2 = False + output = pagenumber + img0 = image.ComicPage(split[0], options.profile) + applyImgOptimization(img0, True, toRight1, options) + img0.saveToDir(dirpath, options.forcepng, options.forcecolor) + img1 = image.ComicPage(split[1], options.profile) + applyImgOptimization(img1, True, toRight2, options) + img1.saveToDir(dirpath, options.forcepng, options.forcecolor) + else: + applyImgOptimization(img, False, False, options) + img.saveToDir(dirpath, options.forcepng, options.forcecolor, split) + return output def genEpubStruct(path): @@ -387,8 +395,8 @@ def genEpubStruct(path): sanitizeTree(os.path.join(path, 'OEBPS', 'Images')) os.mkdir(os.path.join(path, 'OEBPS', 'Text')) f = open(os.path.join(path, 'OEBPS', 'Text', 'style.css'), 'w') - #DON'T COMPRESS CSS. KINDLE WILL FAIL TO PARSE IT. - #Generic Panel View support + Margins fix for Non-Kindle devices. + # DON'T COMPRESS CSS. KINDLE WILL FAIL TO PARSE IT. + # Generic Panel View support + Margins fix for Non-Kindle devices. f.writelines(["@page {\n", "margin-bottom: 0;\n", "margin-top: 0\n", @@ -511,13 +519,6 @@ def genEpubStruct(path): for afile in filenames: filename = getImageFileName(afile) if filename is not None: - if "credit" in afile.lower(): - os.rename(os.path.join(dirpath, afile), os.path.join(dirpath, 'ZZZ999_' + afile)) - afile = 'ZZZ999_' + afile - if "+" in afile.lower() or "#" in afile.lower(): - newfilename = afile.replace('+', '_').replace('#', '_') - os.rename(os.path.join(dirpath, afile), os.path.join(dirpath, newfilename)) - afile = newfilename filelist.append(buildHTML(dirpath, afile)) if not chapter: chapterlist.append((dirpath.replace('Images', 'Text'), filelist[-1][1])) @@ -598,11 +599,11 @@ def sanitizeTree(filetree): def Copyright(): print ('comic2ebook v%(__version__)s. ' - 'Written 2012 by Ciro Mattia Gonano.' % globals()) + 'Written 2013 by Ciro Mattia Gonano and Pawel Jastrzebski.' % globals()) def Usage(): - print "Generates HTML, NCX and OPF for a Comic ebook from a bunch of images." + print "Generates EPUB/CBZ comic ebook from a bunch of images." parser.print_help() @@ -621,8 +622,6 @@ def main(argv=None): help="Outputs a CBZ archive and does not generate EPUB") parser.add_option("--nopanelviewhq", action="store_true", dest="nopanelviewhq", default=False, help="Disable high quality Panel View [Default=False]") - parser.add_option("--panelviewhorizontal", action="store_true", dest="panelviewhorizontal", default=False, - help="Enable horizontal Panel View [Default=False]") parser.add_option("--noprocessing", action="store_false", dest="imgproc", default=True, help="Do not apply image preprocessing (Page splitting and optimizations) [Default=True]") parser.add_option("--forcepng", action="store_true", dest="forcepng", default=False, @@ -696,25 +695,33 @@ def getOutputFilename(srcpath, wantedname, ext): def checkOptions(): global options + # Landscape mode is only supported by Kindle Touch and Paperwhite. if options.profile == 'K4T' or options.profile == 'KHD': options.landscapemode = True else: options.landscapemode = False + # Older Kindle don't support Virtual Panel View. We providing them configuration that will fake that feature. if options.profile == 'K3' or options.profile == 'K4NT': - #Real Panel View + # Real Panel View options.panelview = True else: - #Virtual Panel View + # Virtual Panel View options.panelview = False + # Older Kindle don't need higher resolution files due lack of Panel View. + # Kindle Fire family have very high resolution. Bigger images are not needed. if options.profile == 'K1' or options.profile == 'K2' or options.profile == 'KDX' or options.profile == 'KDXG'\ or options.profile == 'KF' or options.profile == 'KFHD' or options.profile == 'KFHD8': options.nopanelviewhq = True + # Disabling grayscale conversion for Kindle Fire family. + # Forcing JPEG output. For now code can't provide color PNG files. if options.profile == 'KF' or options.profile == 'KFHD' or options.profile == 'KFHD8': options.forcecolor = True options.forcepng = False else: options.forcecolor = False - if options.panelviewhorizontal: + # Mixing vertical and horizontal pages require real Panel View. + # Landscape mode don't work correcly without Virtual Panel View. + if options.rotate: options.panelview = True options.landscapemode = False @@ -723,6 +730,7 @@ def getEpubPath(): global epub_path return epub_path + if __name__ == "__main__": Copyright() main(sys.argv[1:]) diff --git a/kcc/image.py b/kcc/image.py index 2b2da34..4ce1a1e 100755 --- a/kcc/image.py +++ b/kcc/image.py @@ -20,7 +20,7 @@ __copyright__ = '2012-2013, Ciro Mattia Gonano ' __docformat__ = 'restructuredtext en' import os -from PIL import Image, ImageOps, ImageStat +from PIL import Image, ImageOps, ImageStat, ImageChops class ImageFlags: @@ -119,16 +119,21 @@ class ComicPage: raise RuntimeError('Cannot read image file %s' % source) self.image = self.image.convert('RGB') - def saveToDir(self, targetdir, forcepng, color=False): + def saveToDir(self, targetdir, forcepng, color, sufix=None): filename = os.path.basename(self.origFileName) try: if not color: self.image = self.image.convert('L') # convert to grayscale + # Sufix is used to recognise which files need horizontal Panel View. + if sufix == "R": + sufix = "_rotated" + else: + sufix = "" os.remove(os.path.join(targetdir, filename)) if forcepng: - self.image.save(os.path.join(targetdir, os.path.splitext(filename)[0] + ".png"), "PNG") + self.image.save(os.path.join(targetdir, os.path.splitext(filename)[0] + sufix + ".png"), "PNG") else: - self.image.save(os.path.join(targetdir, os.path.splitext(filename)[0] + ".jpg"), "JPEG") + self.image.save(os.path.join(targetdir, os.path.splitext(filename)[0] + sufix + ".jpg"), "JPEG") except IOError as e: raise RuntimeError('Cannot write image in directory %s: %s' % (targetdir, e)) @@ -202,7 +207,7 @@ class ComicPage: if (width > height) != (dstwidth > dstheight): if rotate: self.image = self.image.rotate(90) - return None + return "R" else: if width > height: # source is landscape, so split by the width @@ -232,95 +237,97 @@ class ComicPage: return None def cutPageNumber(self): - widthImg, heightImg = self.image.size - delta = 2 - diff = delta - fixedThreshold = 5 - 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: + if ImageChops.invert(self.image).getbbox() is not None: + widthImg, heightImg = self.image.size + delta = 2 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: + fixedThreshold = 5 + 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 - 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: + 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 - 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)) + 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)) return self.image def cropWhiteSpace(self, threshold): - widthImg, heightImg = self.image.size - delta = 10 - diff = delta - # top - 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)) - widthImg, heightImg = self.image.size - diff = delta - # left - 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)) - 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: - diff += delta - diff -= delta - # print "Down crop: %s"%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: - diff += delta - diff -= delta - # print "Right crop: %s"%diff - self.image = self.image.crop((0, 0, widthImg - diff, heightImg)) - # print "New size: %sx%s"%(self.image.size[0],self.image.size[1]) + 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] < threshold and diff < heightImg: + diff += delta + diff -= delta + # print "Top crop: %s"%diff + 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: + diff += delta + diff -= delta + # print "Left crop: %s"%diff + 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: + diff += delta + diff -= delta + # print "Down crop: %s"%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: + diff += delta + diff -= delta + # print "Right crop: %s"%diff + 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):