diff options
author | Ciro Mattia Gonano <ciromattia@gmail.com> | 2013-01-16 09:53:23 +0100 |
---|---|---|
committer | Ciro Mattia Gonano <ciromattia@gmail.com> | 2013-01-16 09:53:23 +0100 |
commit | d823afc3f931b31d963504e5fc3a8eb3a4b2932d (patch) | |
tree | 28a0709d835be0934a8a3b42c3dc6def09b4dc5a /kcc/image.py | |
parent | Add PDF jpg image extraction (fixes #2) (diff) | |
download | kcc-d823afc3f931b31d963504e5fc3a8eb3a4b2932d.tar.gz kcc-d823afc3f931b31d963504e5fc3a8eb3a4b2932d.tar.bz2 kcc-d823afc3f931b31d963504e5fc3a8eb3a4b2932d.zip |
More work on GUI, added page number cut and other patches to image.py from proDOOMman and Birua (kudos in README)
Diffstat (limited to 'kcc/image.py')
-rwxr-xr-x | kcc/image.py | 184 |
1 files changed, 148 insertions, 36 deletions
diff --git a/kcc/image.py b/kcc/image.py index d072a78..c6042ce 100755 --- a/kcc/image.py +++ b/kcc/image.py @@ -1,4 +1,6 @@ # Copyright (C) 2010 Alex Yatskov +# Copyright (C) 2011 Stanislav (proDOOMman) Kosolapov <prodoomman@gmail.com> +# Copyright (C) 2012-2013 Ciro Mattia Gonano <ciromattia@gmail.com> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -14,7 +16,7 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. import os -from PIL import Image, ImageDraw +from PIL import Image, ImageDraw, ImageStat class ImageFlags: Orient = 1 << 0 @@ -32,7 +34,7 @@ class ProfileData: 0xff, 0xff, 0xff ] - Palette15a = [ + Palette15 = [ 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x22, 0x22, 0x22, @@ -50,13 +52,14 @@ class ProfileData: 0xff, 0xff, 0xff, ] - Palette15b = [ + Palette16 = [ 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x22, 0x22, 0x22, 0x33, 0x33, 0x33, 0x44, 0x44, 0x44, 0x55, 0x55, 0x55, + 0x66, 0x66, 0x66, 0x77, 0x77, 0x77, 0x88, 0x88, 0x88, 0x99, 0x99, 0x99, @@ -69,18 +72,19 @@ class ProfileData: ] Profiles = { - 'K1': ((600, 800), Palette4), - 'K2': ((600, 800), Palette15a), - 'K3': ((600, 800), Palette15a), - 'K4': ((600, 800), Palette15b), - 'KHD': ((758, 1024), Palette15b), - 'KDX': ((824, 1200), Palette15a) + 'K1': ("Kindle", (600, 800), Palette4), + 'K2': ("Kindle 2", (600, 800), Palette15), + 'K3': ("Kindle 3/Keyboard", (600, 800), Palette16), + 'K4': ("Kindle 4/NT/Touch", (600, 800), Palette16), + 'KHD': ("Kindle Paperwhite", (758, 1024), Palette16), + 'KDX': ("Kindle DX", (824, 1200), Palette15), + 'KDXG': ("Kindle DXG", (824, 1200), Palette16) } class ComicPage: def __init__(self,source,device): try: - self.size, self.palette = ProfileData.Profiles[device] + self.profile_label, self.size, self.palette = ProfileData.Profiles[device] except KeyError: raise RuntimeError('Unexpected output device %s' % device) try: @@ -102,15 +106,21 @@ class ComicPage: def quantizeImage(self): colors = len(self.palette) / 3 if colors < 256: - palette = self.palette + self.palette[:3] * (256 - colors) + self.palette = self.palette + self.palette[:3] * (256 - colors) palImg = Image.new('P', (1, 1)) - palImg.putpalette(palette) + palImg.putpalette(self.palette) self.image = self.image.quantize(palette=palImg) def stretchImage(self): widthDev, heightDev = self.size self.image = self.image.resize((widthDev, heightDev), Image.ANTIALIAS) + # TODO: + # - add option to stretch page + # - add option to upscale page + # - if ratio is not equal to dev size and stretch is not enabled, add white + # background and center it (otherwise K3 does not display page + # center-aligned but left-aligned) def resizeImage(self): widthDev, heightDev = self.size widthImg, heightImg = self.image.size @@ -129,19 +139,13 @@ class ComicPage: widthImg, heightImg = self.size self.image = self.image.resize((widthImg, heightImg), Image.ANTIALIAS) - def orientImage(self): - widthDev, heightDev = self.size - widthImg, heightImg = self.image.size - if (widthImg > heightImg) != (widthDev > heightDev): - self.image = self.image.rotate(90, Image.BICUBIC, True) - def splitPage(self, targetdir, righttoleft=False): width, height = self.image.size dstwidth, dstheight = self.size print "Image is %d x %d" % (width,height) # only split if origin is not oriented the same as target if (width > height) != (dstwidth > dstheight): - if (width > height): + if width > height: # source is landscape, so split by the width leftbox = (0, 0, width/2, height) rightbox = (width/2, 0, width, height) @@ -153,7 +157,7 @@ class ComicPage: fileone = targetdir + '/' + filename[0] + '-1' + filename[1] filetwo = targetdir + '/' + filename[0] + '-2' + filename[1] try: - if (righttoleft == True): + if righttoleft: pageone = self.image.crop(rightbox) pagetwo = self.image.crop(leftbox) else: @@ -164,7 +168,7 @@ class ComicPage: os.remove(self.origFileName) except IOError as e: raise RuntimeError('Cannot write image in directory %s: %s' %(targetdir,e)) - return (fileone,filetwo) + return fileone,filetwo return None def frameImage(self): @@ -190,18 +194,126 @@ class ComicPage: draw.rectangle([corner1, corner2], outline=foreground) self.image = imageBg -# for debug purposes (this file is not meant to be called directly -if __name__ == "__main__": - import sys - imgfile = sys.argv[1] - img = ComicPage(imgfile, "KHD") - pages = img.splitPage('temp/',False) - if (pages != None): - print "%s, %s" % pages - sys.exit(0) - img.orientImage() - img.resizeImage() - img.frameImage() - img.quantizeImage() - img.saveToDir("temp/") - sys.exit(0) + + 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: + 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)) + 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]) + return self.image + + def addProgressbar(self, file_number, files_totalnumber, size, howoften): + if file_number//howoften!=float(file_number)/howoften: + return self.image + 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.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) + #White rectangle + 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 + else: + 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) + return self.image + |