root / pkpgcounter / trunk / pkpgpdls / inkcoverage.py @ 3578

Revision 3578, 4.3 kB (checked in by jerome, 5 years ago)

Clarified dependency wrt PIL/Pillow.
Updated copyright years.
Regenerated manual page.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Revision Id
Line 
1# -*- coding: utf-8 -*-
2#
3# pkpgcounter : a generic Page Description Language parser
4#
5# (c) 2003-2019 Jerome Alet <alet@librelogiciel.com>
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program.  If not, see <http://www.gnu.org/licenses/>.
18#
19# $Id$
20#
21
22"""This modules implements the computation of ink coverage in different colorspaces."""
23
24import sys
25
26import pdlparser
27
28try :
29    from PIL import Image
30except ImportError :
31    sys.stderr.write("ERROR: You MUST install the Python Imaging Library (either PIL or Pillow) for pkpgcounter to work.\n")
32    raise pdlparser.PDLParserError, "The Python Imaging Library is missing."
33
34def getPercent(img, nbpix) :
35    """Extracts the percents per color component from a picture."""
36    result = {}
37    bands = img.split()
38    for (i, bandname) in enumerate(img.getbands()) :
39        result[bandname] = 100.0 * (reduce(lambda current, next: current + (next[1] * next[0]), enumerate(bands[i].histogram()), 0) / 255.0) / nbpix
40    return result
41
42def getPercentCMYK(img, nbpix) :
43    """Extracts the percents of Cyan, Magenta, Yellow, and Black from a picture.
44
45       PIL doesn't produce useable CMYK for our algorithm, so we use the algorithm from PrintBill.
46    """
47    if img.mode != "RGB" :
48        img = img.convert("RGB")
49    cyan = magenta = yellow = black = 0
50    for (r, g, b) in img.getdata() :
51        pixblack = 255 - max(r, g, b)
52        black += pixblack
53        cyan += 255 - r - pixblack
54        magenta += 255 - g - pixblack
55        yellow += 255 - b - pixblack
56
57    frac = 100.0 / nbpix
58    return { "C" : frac * (cyan / 255.0),
59             "M" : frac * (magenta / 255.0),
60             "Y" : frac * (yellow / 255.0),
61             "K" : frac * (black / 255.0),
62           }
63
64def getPercentGC(img, nbpix) :
65    """Determines if a page is in grayscale or colour mode."""
66    if img.mode != "RGB" :
67        img = img.convert("RGB")
68    gray = 0
69    for (r, g, b) in img.getdata() :
70        if not (r == g == b) :
71            # optimize : if a single pixel is not gray the whole page is colored.
72            return { "G" : 0.0, "C" : 100.0 }
73    return { "G" : 100.0, "C" : 0.0 }
74
75def getPercentBW(img, nbpix) :
76    """Extracts the percents of Black from a picture, once converted to gray levels."""
77    if img.mode != "L" :
78        img = img.convert("L")
79    return { "B" : 100.0 - getPercent(img, nbpix)["L"] }
80
81def getPercentRGB(img, nbpix) :
82    """Extracts the percents of Red, Green, Blue from a picture, once converted to RGB."""
83    if img.mode != "RGB" :
84        img = img.convert("RGB")
85    return getPercent(img, nbpix)
86
87def getPercentCMY(img, nbpix) :
88    """Extracts the percents of Cyan, Magenta, and Yellow from a picture once converted to RGB."""
89    result = getPercentRGB(img, nbpix)
90    return { "C" : 100.0 - result["R"],
91             "M" : 100.0 - result["G"],
92             "Y" : 100.0 - result["B"],
93           }
94
95def getInkCoverage(fname, colorspace) :
96    """Returns a list of dictionnaries containing for each page,
97       for each color component, the percent of ink coverage on
98       that particular page.
99    """
100    result = []
101    colorspace = colorspace.upper()
102    computation = globals()["getPercent%s" % colorspace]
103    index = 0
104    try :
105        image = Image.open(fname)
106    except (IOError, OverflowError), msg :
107        raise pdlparser.PDLParserError, "%s (%s)" % (msg, fname)
108    else :
109        try :
110            while True :
111                nbpixels = image.size[0] * image.size[1]
112                result.append(computation(image, nbpixels))
113                index += 1
114                image.seek(index)
115        except EOFError :
116            pass
117        return (colorspace, result)
118
119if __name__ == "__main__" :
120    # NB : length of result gives number of pages !
121    sys.stdout.write("%s\n" % getInkCoverage(sys.argv[1], "CMYK"))
Note: See TracBrowser for help on using the browser.