root / pykota / trunk / bin / pkbanner @ 1936

Revision 1936, 13.7 kB (checked in by jalet, 19 years ago)

Improved pkbanner's help

  • 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# A banner generator for PyKota
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.9  2004/11/17 13:24:05  jalet
27# Improved pkbanner's help
28#
29# Revision 1.8  2004/11/17 13:12:04  jalet
30# Implemented the --savetoner command line option
31#
32# Revision 1.7  2004/11/15 22:29:01  jalet
33# Moved title and filename to the left to free some space.
34#
35# Revision 1.6  2004/11/15 22:20:27  jalet
36# Now outputs strings as-is, and not title-ized
37#
38# Revision 1.5  2004/11/15 22:01:34  jalet
39# Improved banner handling.
40# Fix for raw printing and banners.
41#
42# Revision 1.4  2004/11/15 19:59:34  jalet
43# PyKota banners now basically work !
44#
45# Revision 1.3  2004/11/12 23:46:44  jalet
46# Heavy work on pkbanner. Not finished yet though, but mostly works.
47#
48# Revision 1.2  2004/11/11 14:25:48  jalet
49# Added some TODO comments
50#
51# Revision 1.1  2004/11/10 22:48:47  jalet
52# Banner generator's skeleton added
53#
54#
55#
56
57import sys
58import os
59import time
60import cStringIO
61import popen2
62
63try :
64    from reportlab.pdfgen import canvas
65    from reportlab.lib import pagesizes
66    from reportlab.lib.units import cm
67except ImportError :   
68    hasRL = 0
69else :   
70    hasRL = 1
71   
72try :
73    import PIL.Image 
74except ImportError :   
75    hasPIL = 0
76else :   
77    hasPIL = 1
78   
79from pykota.tool import Tool, PyKotaToolError, crashed, N_
80
81__doc__ = N_("""pkbanner v%s (c) 2003-2004 C@LL - Conseil Internet & Logiciels Libres
82
83Generates banners.
84
85command line usage :
86
87  pkbanner  [options]
88
89options :
90
91  -v | --version       Prints pkbanner's version number then exits.
92  -h | --help          Prints this message then exits.
93 
94  -l | --logo img      Use the image as the banner's logo. The logo will
95                       be drawn at the top center of the page. The default
96                       logo is /usr/share/pykota/logos/pykota.jpeg
97                       
98  -p | --pagesize sz   Sets sz as the page size. Most well known
99                       page sizes are recognized, like 'A4' or 'Letter'
100                       to name a few. The default size is A4.
101 
102  -s | --savetoner s   Sets the text luminosity factor to d%%. This can be
103                       used to save toner. The default value is 0, which
104                       means that no toner saving will be done.
105 
106  -u | --url u         Uses u as an url to be written at the bottom of
107                       the banner page. The default url is :
108                       http://www.librelogiciel.com/software/
109 
110examples :                             
111
112  Using pkbanner directly from the command line is not recommended,
113  excepted for testing purposes. You should use pkbanner in the
114  'startingbanner' or 'endingbanner' directives in pykota.conf
115 
116    startingbanner: /usr/bin/pkbanner --logo="" --savetoner=75
117 
118      With such a setting in pykota.conf, all print jobs will be
119      prefixed with an A4 banner with no logo, and text luminosity will
120      be increased by 75%%. The PostScript output will be directly sent
121      to your printer.
122     
123  You'll find more examples in the sample configuration file included   
124  in PyKota.
125     
126This program is free software; you can redistribute it and/or modify
127it under the terms of the GNU General Public License as published by
128the Free Software Foundation; either version 2 of the License, or
129(at your option) any later version.
130
131This program is distributed in the hope that it will be useful,
132but WITHOUT ANY WARRANTY; without even the implied warranty of
133MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
134GNU General Public License for more details.
135
136You should have received a copy of the GNU General Public License
137along with this program; if not, write to the Free Software
138Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
139
140Please e-mail bugs to: %s""")
141       
142class PyKotaBanner(Tool) :       
143    """A class for pkbanner."""
144    def getPageSize(self, pgsize) :
145        """Returns the correct page size or None if not found."""
146        try :
147            return getattr(pagesizes, pgsize.upper())
148        except AttributeError :   
149            try :
150                return getattr(pagesizes, pgsize.lower())
151            except AttributeError :
152                pass
153               
154    def getVar(self, varname) :           
155        """Extracts a variable from the environment and returns its value or 'Unknown' in the current locale."""
156        return os.environ.get(varname) or _("Unknown")
157       
158    def printVar(self, canvas, x, y, label, value, size, savetoner) :
159        """Outputs a variable onto the PDF canvas.
160       
161           Returns the number of points to substract to current Y coordinate.
162        """   
163        canvas.saveState()
164        canvas.setFont("Helvetica-Bold", size)
165        (r, g, b) =  [ color + (savetoner * (1.0 - color)) for color in (0, 0, 0) ] # Black * savetoner
166        canvas.setFillColorRGB(r, g, b)
167        message = "%s :" % _(label)
168        canvas.drawRightString(x, y, message)
169        canvas.setFont("Courier-Bold", size)
170        (r, g, b) =  [ color + (savetoner * (1.0 - color)) for color in (1, 0, 0) ] # Red * savetoner
171        canvas.setFillColorRGB(r, g, b)
172        canvas.drawString(x + 0.5*cm, y, value)
173        canvas.restoreState()
174        return (size + 4)
175   
176    def genPDF(self, pagesize, logo, url, savetoner) :
177        """Generates the banner in PDF format, return the PDF document as a string."""
178       
179        document = cStringIO.StringIO()
180        c = canvas.Canvas(document, pagesize=pagesize, pageCompression=1)
181       
182        c.setAuthor("Jerome Alet")
183        c.setTitle("PyKota generated Banner")
184        c.setSubject("This is a print banner generated with PyKota")
185       
186        xcenter = pagesize[0] / 2.0
187        ycenter = pagesize[1] / 2.0
188                   
189        ypos = pagesize[1] - (2 * cm)           
190       
191        if logo :
192            try :   
193                imglogo = PIL.Image.open(logo)
194            except :   
195                self.printInfo("Unable to open image %s" % logo, "warn")
196            else :
197                (width, height) = imglogo.size
198                multi = float(width) / (8 * cm) 
199                width = float(width) / multi
200                height = float(height) / multi
201                xpos = xcenter - (width / 2.0)
202                ypos -= height
203                c.drawImage(logo, xpos, ypos, width, height)
204       
205        # New top
206        xpos = pagesize[0] / 5.0
207        ypos -= (1 * cm) + 20
208       
209        printername = self.getVar("PYKOTAPRINTERNAME")
210        username = self.getVar("PYKOTAUSERNAME")
211        accountbanner = self.config.getAccountBanner(printername)
212       
213        # Outputs the username
214        ypos -= self.printVar(c, xcenter, ypos, _("Username"), username, 20, savetoner) 
215       
216        # Printer and Job Id
217        job = "%s - %s" % (printername, self.getVar("PYKOTAJOBID"))
218        ypos -= self.printVar(c, xcenter, ypos, _("Job"), job, 14, savetoner) 
219       
220        # Current date (TODO : at the time the banner was printed ! Change this to job's submission date)
221        datetime = time.strftime("%c", time.localtime())
222        ypos -= self.printVar(c, xcenter, ypos, _("Date"), datetime, 14, savetoner) 
223       
224        # Result of the print job
225        action = self.getVar("PYKOTAACTION")
226        if action == "ALLOW" :
227            action = _("Allowed")
228        elif action == "DENY" :   
229            action = _("Denied")
230        elif action == "WARN" :   
231            action = _("Allowed with Warning")
232        ypos -= self.printVar(c, xcenter, ypos, _("Result"), action, 14, savetoner) 
233       
234        # skip some space
235        ypos -= 20
236       
237        # Outputs title and filename
238        # We put them at x=0.25*pagewidth so that the line is long enough to hold them
239        title = self.getVar("PYKOTATITLE")
240        ypos -= self.printVar(c, xcenter / 2.0, ypos, _("Title"), title, 10, savetoner) 
241       
242        filename = self.getVar("PYKOTAFILENAME")
243        ypos -= self.printVar(c, xcenter / 2.0, ypos, _("Filename"), filename, 10, savetoner) 
244       
245        # skip some space
246        ypos -= 20
247       
248        # Now outputs the user's account balance or page counter
249        ypos -= self.printVar(c, xcenter, ypos, _("Pages printed so far on %s") % printername, self.getVar("PYKOTAPAGECOUNTER"), 14, savetoner) 
250        limitby = self.getVar("PYKOTALIMITBY")
251        if limitby == "balance" : 
252            ypos -= self.printVar(c, xcenter, ypos, _("Account balance"), self.getVar("PYKOTABALANCE"), 14, savetoner) 
253        else :
254            ypos -= self.printVar(c, xcenter, ypos, _("Soft Limit"), self.getVar("PYKOTASOFTLIMIT"), 14, savetoner) 
255            ypos -= self.printVar(c, xcenter, ypos, _("Hard Limit"), self.getVar("PYKOTAHARDLIMIT"), 14, savetoner) 
256            ypos -= self.printVar(c, xcenter, ypos, _("Date Limit"), self.getVar("PYKOTADATELIMIT"), 14, savetoner) 
257           
258        # URL
259        if url :
260            c.saveState()
261            c.setFont("Courier-Bold", 16)
262            (r, g, b) =  [ color + (savetoner * (1.0 - color)) for color in (0, 0, 1) ] # Blue * savetoner
263            c.setFillColorRGB(r, g, b)
264            c.drawCentredString(xcenter, 2 * cm, url)
265            c.restoreState()
266       
267        c.showPage()
268        c.save()
269        return document.getvalue()
270       
271    def main(self, files, options) :
272        """Generates a banner."""
273        if not hasRL :
274            raise PyKotaToolError, "The ReportLab module is missing. Download it from http://www.reportlab.org"
275        if not hasPIL :
276            raise PyKotaToolError, "The Python Imaging Library is missing. Download it from http://www.pythonware.com/downloads"
277           
278        try :
279            savetoner = int(options["savetoner"])
280            if (savetoner < 0) or (savetoner > 99) :
281                raise ValueError, _("Allowed range is (0..99)")
282            savetoner /= 100.0   
283        except (TypeError, ValueError), msg :
284            self.printInfo(_("Invalid 'savetoner' option %s : %s") % (options["savetoner"], msg), "warn")
285            savetoner = 0.0
286           
287        pagesize = self.getPageSize(options["pagesize"])
288        if pagesize is None :
289            pagesize = self.getPageSize("a4")
290            self.printInfo(_("Invalid 'pagesize' option %s, defaulting to A4.") % options["pagesize"], "warn")
291           
292        self.logdebug("Generating the banner in PDF format...")   
293        doc = self.genPDF(pagesize, options["logo"].strip(), options["url"].strip(), savetoner)
294       
295        self.logdebug("Converting the banner to PostScript...")   
296        os.environ["PATH"] = "%s:/bin:/usr/bin:/usr/local/bin:/opt/bin:/sbin:/usr/sbin" % os.environ.get("PATH", "")
297        child = popen2.Popen3("gs -q -dNOPAUSE -dBATCH -dPARANOIDSAFER -sDEVICE=pswrite -sOutputFile=- - 2>/tmp/errgs")
298        child.tochild.write(doc)
299        child.tochild.close()
300        sys.stdout.write(child.fromchild.read())
301        sys.stdout.flush()
302        child.fromchild.close()
303        status = child.wait()
304        if os.WIFEXITED(status) :
305            status = os.WEXITSTATUS(status)
306        self.logdebug("PDF to PostScript converter exit code is %s" % str(status))
307        self.logdebug("Banner completed.")
308        return status
309
310if __name__ == "__main__" :
311    # TODO : --papertray : to print banners on a different paper (colored for example)
312    retcode = 0
313    try :
314        defaults = { \
315                     "savetoner" : "100", \
316                     "pagesize" : "a4", \
317                     "logo" : "/usr/share/pykota/logos/pykota.jpeg",
318                     "url" : "http://www.librelogiciel.com/software/",
319                   }
320        short_options = "vhs:l:p:u:"
321        long_options = ["help", "version", "savetoner=", "pagesize=", "logo=", "url="]
322       
323        # Initializes the command line tool
324        banner = PyKotaBanner(doc=__doc__)
325       
326        # parse and checks the command line
327        (options, args) = banner.parseCommandline(sys.argv[1:], short_options, long_options, allownothing=1)
328       
329        # sets long options
330        options["help"] = options["h"] or options["help"]
331        options["version"] = options["v"] or options["version"]
332        options["savetoner"] = options["s"] or options["savetoner"] or defaults["savetoner"]
333        options["pagesize"] = options["p"] or options["pagesize"] or defaults["pagesize"]
334        options["url"] = options["u"] or options["url"] or defaults["url"]
335       
336        options["logo"] = options["l"] or options["logo"]
337        if options["logo"] is None : # Allows --logo="" to disable the logo entirely
338            options["logo"] = defaults["logo"] 
339       
340        if options["help"] :
341            banner.display_usage_and_quit()
342        elif options["version"] :
343            banner.display_version_and_quit()
344        else :
345            retcode = banner.main(args, options)
346    except SystemExit :       
347        pass
348    except :
349        try :
350            banner.crashed("pkbanner failed")
351        except :   
352            crashed("pkbanner failed")
353        retcode = -1
354       
355    sys.exit(retcode)   
Note: See TracBrowser for help on using the browser.