root / pkpgcounter / trunk / pkpgpdls / analyzer.py @ 350

Revision 350, 7.6 kB (checked in by jerome, 18 years ago)

Now accepts --colorspace bw | cmyk | cmy | all
and --resolution x (in DPI) on the command line, as a preliminary
before implementing the computation of ink usage.

  • Property svn:keywords set to Auth Date Id Rev
RevLine 
[200]1#
2# pkpgcounter : a generic Page Description Language parser
3#
[303]4# (c) 2003, 2004, 2005, 2006 Jerome Alet <alet@librelogiciel.com>
[200]5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
[211]17# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
[200]18#
19# $Id$
20#
21
22import sys
23import tempfile
24
[235]25import version, pdlparser, postscript, pdf, pcl345, pclxl, \
[328]26       escp2, dvi, tiff, ooo, zjstream
[200]27
28class PDLAnalyzer :   
29    """Class for PDL autodetection."""
30    def __init__(self, filename, debug=0) :
31        """Initializes the PDL analyzer.
32       
33           filename is the name of the file or '-' for stdin.
34           filename can also be a file-like object which
35           supports read() and seek().
36        """
37        self.debug = debug
38        self.filename = filename
39       
40    def getJobSize(self) :   
41        """Returns the job's size."""
42        self.openFile()
43        try :
44            pdlhandler = self.detectPDLHandler()
45        except pdlparser.PDLParserError, msg :   
46            self.closeFile()
[220]47            raise pdlparser.PDLParserError, "Unknown file format for %s (%s)" % (self.filename, msg)
[200]48        else :
49            try :
[220]50                size = pdlhandler.getJobSize()
[200]51            finally :   
52                self.closeFile()
53            return size
54       
55    def openFile(self) :   
56        """Opens the job's data stream for reading."""
57        self.mustclose = 0  # by default we don't want to close the file when finished
58        if hasattr(self.filename, "read") and hasattr(self.filename, "seek") :
59            # filename is in fact a file-like object
60            infile = self.filename
61        elif self.filename == "-" :
62            # we must read from stdin
63            infile = sys.stdin
64        else :   
65            # normal file
66            self.infile = open(self.filename, "rb")
67            self.mustclose = 1
68            return
69           
70        # Use a temporary file, always seekable contrary to standard input.
71        self.infile = tempfile.TemporaryFile(mode="w+b")
72        while 1 :
[220]73            data = infile.read(pdlparser.MEGABYTE) 
[200]74            if not data :
75                break
76            self.infile.write(data)
77        self.infile.flush()   
78        self.infile.seek(0)
79           
80    def closeFile(self) :       
81        """Closes the job's data stream if we can close it."""
82        if self.mustclose :
83            self.infile.close()   
84        else :   
85            # if we don't have to close the file, then
86            # ensure the file pointer is reset to the
87            # start of the file in case the process wants
88            # to read the file again.
89            try :
90                self.infile.seek(0)
91            except :   
92                pass    # probably stdin, which is not seekable
93       
94    def detectPDLHandler(self) :   
95        """Tries to autodetect the document format.
96       
97           Returns the correct PDL handler class or None if format is unknown
98        """   
[220]99        # Try to detect file type by reading first and last blocks of datas   
100        # Each parser can read them automatically, but here we do this only once.
[200]101        self.infile.seek(0)
[220]102        firstblock = self.infile.read(pdlparser.FIRSTBLOCKSIZE)
[200]103        try :
[220]104            self.infile.seek(-pdlparser.LASTBLOCKSIZE, 2)
105            lastblock = self.infile.read(pdlparser.LASTBLOCKSIZE)
[200]106        except IOError :   
107            lastblock = ""
108        self.infile.seek(0)
[217]109        if not firstblock :
[220]110            raise pdlparser.PDLParserError, "input file %s is empty !" % str(self.filename)
[200]111        else :   
[220]112            for module in (postscript, \
113                           pclxl, \
114                           pdf, \
115                           pcl345, \
116                           escp2, \
117                           dvi, \
[229]118                           tiff, \
[328]119                           zjstream, \
[229]120                           ooo) :
[220]121                try :               
[252]122                    return module.Parser(self.infile, self.debug, firstblock, lastblock)
[220]123                except pdlparser.PDLParserError :
124                    pass # try next parser
[217]125        raise pdlparser.PDLParserError, "Analysis of first data block failed."
[200]126           
127def main() :   
128    """Entry point for PDL Analyzer."""
[350]129    import optparse
130    from copy import copy
131   
132    def check_cichoice(option, opt, value) :
133        """To add a CaseIgnore Choice option type."""
134        valower = value.lower()
135        if valower in [v.lower() for v in option.cichoices] :
136            return valower
137        else :   
138            choices = ", ".join(map(repr, option.cichoices))
139            raise optparse.OptionValueError(
140                "option %s: invalid choice: %r (choose from %s)"
141                % (opt, value, choices))
142   
143    class MyOption(optparse.Option) :
144        """New Option class, with CaseIgnore Choice type."""
145        TYPES = optparse.Option.TYPES + ("cichoice",)
146        ATTRS = optparse.Option.ATTRS + ["cichoices"]
147        TYPE_CHECKER = copy(optparse.Option.TYPE_CHECKER)
148        TYPE_CHECKER["cichoice"] = check_cichoice
149       
150    parser = optparse.OptionParser(option_class=MyOption, 
151                                   usage="python analyzer.py [options] file1 [file2 ...]")
[348]152    parser.add_option("-v", "--version", 
153                            action="store_true", 
154                            dest="version",
[350]155                            help="Show pkpgcounter's version number and exit.")
[348]156    parser.add_option("-d", "--debug", 
157                            action="store_true", 
158                            dest="debug",
[350]159                            help="Activate debug mode.")
160    parser.add_option("-c", "--colorspace", 
161                            dest="colorspace",
162                            type="cichoice",
163                            cichoices=["bw", "cmyk", "cmy", "all"],
164                            help="Activate the computation of ink usage, and defines the colorspace to use. Supported values are 'BW', 'CMYK', 'CMY' and 'ALL'.")
165    parser.add_option("-r", "--resolution", 
166                            type="int", 
167                            default=150, 
168                            dest="resolution",
169                            help="The resolution in DPI to use when checking ink usage. Lower resolution is faster. Default is 150.")
[348]170    (options, arguments) = parser.parse_args()
171    if options.version :
[200]172        print "%s" % version.__version__
173    else :
[348]174        if (not arguments) or ((not sys.stdin.isatty()) and ("-" not in arguments)) :
175            arguments.append("-")
[200]176        totalsize = 0   
[350]177        try :
178            for arg in arguments :
179                try :
180                    parser = PDLAnalyzer(arg, options.debug)
181                    totalsize += parser.getJobSize()
182                except (IOError, pdlparser.PDLParserError), msg :   
183                    sys.stderr.write("ERROR: %s\n" % msg)
184                    sys.stderr.flush()
185        except KeyboardInterrupt :           
186            sys.stderr.write("WARN: Aborted at user's request.\n")
187            sys.stderr.flush()
[200]188        print "%s" % totalsize
189   
190if __name__ == "__main__" :   
191    main()
Note: See TracBrowser for help on using the browser.