root / pykota / trunk / bin / pkpgcounter @ 1448

Revision 1448, 6.3 kB (checked in by jalet, 20 years ago)

Better PCL support

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1#! /usr/bin/env python
2# -*- coding: ISO-8859-15 -*-
3
4# pkpgcounter, a smart software page counter
5#
6# PyKota - Print Quotas for CUPS and LPRng
7#
8# (c) 2003-2004 Jerome Alet <alet@librelogiciel.com>
9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation; either version 2 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program; if not, write to the Free Software
21# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
22#
23# $Id$
24#
25# $Log$
26# Revision 1.3  2004/05/04 04:39:26  jalet
27# Better PCL support
28#
29# Revision 1.2  2004/05/04 03:14:26  jalet
30# fixed copy&paste problem in pkpgcounter
31#
32# Revision 1.1  2004/04/08 17:07:42  jalet
33# pkpgcounter added
34#
35#
36
37import sys
38import tempfile
39
40def ispostscript(data) :   
41    """Returns 1 if data is PostScript, else 0."""
42    if data.startswith("%!") or \
43       data.startswith("\004%!") or \
44       data.startswith("\033%-12345X%!PS") or \
45       ((data[:128].find("\033%-12345X") != -1) and \
46         ((data.find("LANGUAGE=POSTSCRIPT") != -1) or \
47          (data.find("LANGUAGE = POSTSCRIPT") != -1) or \
48          (data.find("LANGUAGE = Postscript") != -1))) :
49        return 1
50    else :   
51        return 0
52   
53def postscript(infile) :
54    """Count pages in a PostScript document."""
55    pagecount = 0
56    pagenum = None
57    while 1 :
58        line = infile.readline()
59        if not line :
60            break
61        if line.startswith("%%Page: ") :
62            pagecount += 1
63    return pagecount
64   
65def ispcl(data) :   
66    """Returns 1 if data is PCL, else 0."""
67    if data.startswith("\033E\033") or \
68       ((data[:128].find("\033%-12345X") != -1) and \
69         ((data.find("LANGUAGE=PCL") != -1) or \
70          (data.find("LANGUAGE = PCL") != -1) or \
71          (data.find("LANGUAGE = Pcl") != -1))) :
72        return 1
73    else :   
74        return 0
75   
76def pcl(infile) :   
77    """Count pages in a PostScript document."""
78    #
79    # Algorithm from pclcount
80    # (c) 2003, by Eduardo Gielamo Oliveira & Rodolfo Broco Manin
81    # published under the terms of the GNU General Public Licence v2.
82    #
83    # Backported from C to Python by Jerome Alet
84    #
85    tagsends = { "&n" : "W", "&b": "W", "*i" : "W", "*l" : "W", "*m" : "W", "*v": "W", "*c" : "W", "(f" : "W", "*b" : "VW", "(s" : "W", ")s" : "W", "&p" : "X", "&l" : "X" } 
86    copies = 1
87    pagecount = 0
88    tag = None
89    while 1 :
90        char = infile.read(1)   # TODO : speed this up if possible
91        if not char :
92            break
93        if char == "\014" :   
94            pagecount += 1
95        elif char == "\033" :   
96            #
97            #     <ESC>*b###W -> Start of a raster data row/block
98            #     <ESC>*b###V -> Start of a raster data plane
99            #     <ESC>*c###W -> Start of a user defined pattern
100            #     <ESC>*i###W -> Start of a viewing illuminant block
101            #     <ESC>*l###W -> Start of a color lookup table
102            #     <ESC>*m###W -> Start of a download dither matrix block
103            #     <ESC>*v###W -> Start of a configure image data block
104            #     <ESC>(s###W -> Start of a characters description block
105            #     <ESC>)s###W -> Start of a fonts description block
106            #     <ESC>(f###W -> Start of a symbol set block
107            #     <ESC>&b###W -> Start of configuration data block
108            #     <ESC>&l###X -> Number of copies
109            #     <ESC>&n###W -> Starts an alphanumeric string ID block
110            #     <ESC>&p###X -> Start of a non printable characters block
111            #
112            tagstart = infile.read(1)
113            if tagstart in "E9=YZ" : # one byte PCL tag
114                continue             # skip to next tag
115            tag = tagstart + infile.read(1)
116            try :
117                tagend = tagsends[tag]
118            except KeyError :   
119                pass    # Unsupported PCL tag
120            else :   
121                # Now read the numeric argument
122                size = 0
123                while 1 :
124                    char = infile.read(1)
125                    if not char.isdigit() :
126                        break
127                    size = (size * 10) + int(char)   
128                if char in tagend :   
129                    if tag == "&l" :
130                        copies = size
131                    else :   
132                        # doing a read will prevent the seek
133                        # for unseekable streams.
134                        # we just ignore the block anyway.
135                        if tag == "&n" : 
136                            # we have to take care of the operation id byte
137                            # which is before the string itself
138                            size += 1
139                        infile.read(size) 
140    return copies * pagecount       
141
142def smartpagecounter(filename) :
143    """Autodetects file format and returns number of pages."""
144    if filename == "-" :
145        # we must read from stdin
146        # but since stdin is not seekable, we have to use a temporary
147        # file instead.
148        infile = tempfile.TemporaryFile()
149        while 1 :
150            data = sys.stdin.read(256 * 1024) 
151            if not data :
152                break
153            infile.write(data)
154        infile.flush()   
155        infile.seek(0)
156    else :   
157        # normal file
158        infile = open(filename, "rb")
159       
160    # Try to detect file type by reading first block of datas   
161    firstblock = infile.read(1024)
162    infile.seek(0)
163    if ispostscript(firstblock) :
164        size = postscript(infile)
165    elif ispcl(firstblock) :   
166        size = pcl(infile)
167    else :   
168        sys.stderr.write("ERROR : Unknown file format for %s\n" % filename)
169        size = 0
170    infile.close()   
171    return size
172   
173if __name__ == "__main__" :   
174    if len(sys.argv) < 2 :
175        sys.argv.append("-")
176       
177    totalsize = 0   
178    for arg in sys.argv[1:] :
179        totalsize += smartpagecounter(arg)
180    print "%s" % totalsize
Note: See TracBrowser for help on using the browser.