root / pykota / trunk / bin / pkbanner @ 2267

Revision 2267, 13.4 kB (checked in by jerome, 19 years ago)

Moved the copyright strings out of the docstrings

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