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

Revision 351, 7.8 kB (checked in by jerome, 16 years ago)

API change for PDLAnalyzer's constructor.

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