about summary refs log tree commit diff
path: root/kcc/image.py
diff options
context:
space:
mode:
authorCiro Mattia Gonano <ciromattia@gmail.com>2013-01-16 09:53:23 +0100
committerCiro Mattia Gonano <ciromattia@gmail.com>2013-01-16 09:53:23 +0100
commitd823afc3f931b31d963504e5fc3a8eb3a4b2932d (patch)
tree28a0709d835be0934a8a3b42c3dc6def09b4dc5a /kcc/image.py
parentAdd PDF jpg image extraction (fixes #2) (diff)
downloadkcc-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-xkcc/image.py184
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
+