root / pykota / trunk / bin / pkbanner @ 2139

Revision 2139, 14.0 kB (checked in by jerome, 19 years ago)

Added the Log keyword property

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