root / pykota / trunk / bin / pkbanner @ 2147

Revision 2147, 12.9 kB (checked in by jerome, 19 years ago)

Removed all references to $Log$

  • 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, 2005 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#
26
27import sys
28import os
29import time
30import cStringIO
31import popen2
32
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
51__doc__ = N_("""pkbanner v%s (c) 2003, 2004, 2005 C@LL - Conseil Internet & Logiciels Libres
52
53Generates banners.
54
55command line usage :
56
57  pkbanner  [options]
58
59options :
60
61  -v | --version       Prints pkbanner's version number then exits.
62  -h | --help          Prints this message then exits.
63 
64  -l | --logo img      Use the image as the banner's logo. The logo will
65                       be drawn at the center top of the page. The default
66                       logo is /usr/share/pykota/logos/pykota.jpeg
67                       
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 
72  -s | --savetoner s   Sets the text luminosity factor to s%%. This can be
73                       used to save toner. The default value is 0, which
74                       means that no toner saving will be done.
75 
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 
80examples :                             
81
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 
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     
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               
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       
128    def printVar(self, canvas, x, y, label, value, size, savetoner) :
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)
135        (r, g, b) =  [ color + (savetoner * (1.0 - color)) for color in (0, 0, 0) ] # Black * savetoner
136        canvas.setFillColorRGB(r, g, b)
137        message = "%s :" % _(label)
138        canvas.drawRightString(x, y, message)
139        canvas.setFont("Courier-Bold", size)
140        (r, g, b) =  [ color + (savetoner * (1.0 - color)) for color in (1, 0, 0) ] # Red * savetoner
141        canvas.setFillColorRGB(r, g, b)
142        canvas.drawString(x + 0.5*cm, y, value)
143        canvas.restoreState()
144        return (size + 4)
145   
146    def genPDF(self, pagesize, logo, url, savetoner) :
147        """Generates the banner in PDF format, return the PDF document as a string."""
148       
149        document = cStringIO.StringIO()
150        c = canvas.Canvas(document, pagesize=pagesize, pageCompression=1)
151       
152        c.setAuthor("Jerome Alet")
153        c.setTitle("PyKota generated Banner")
154        c.setSubject("This is a print banner generated with PyKota")
155       
156        xcenter = pagesize[0] / 2.0
157        ycenter = pagesize[1] / 2.0
158                   
159        ypos = pagesize[1] - (2 * cm)           
160       
161        if logo :
162            try :   
163                imglogo = PIL.Image.open(logo)
164            except :   
165                self.printInfo("Unable to open image %s" % logo, "warn")
166            else :
167                (width, height) = imglogo.size
168                multi = float(width) / (8 * cm) 
169                width = float(width) / multi
170                height = float(height) / multi
171                xpos = xcenter - (width / 2.0)
172                ypos -= height
173                c.drawImage(logo, xpos, ypos, width, height)
174       
175        # New top
176        xpos = pagesize[0] / 5.0
177        ypos -= (1 * cm) + 20
178       
179        printername = self.getVar("PYKOTAPRINTERNAME")
180        username = self.getVar("PYKOTAUSERNAME")
181        accountbanner = self.config.getAccountBanner(printername)
182       
183        # Outputs the username
184        ypos -= self.printVar(c, xcenter, ypos, _("Username"), username, 20, savetoner) 
185       
186        # Printer and Job Id
187        job = "%s - %s" % (printername, self.getVar("PYKOTAJOBID"))
188        ypos -= self.printVar(c, xcenter, ypos, _("Job"), job, 14, savetoner) 
189       
190        # Current date (TODO : at the time the banner was printed ! Change this to job's submission date)
191        datetime = time.strftime("%c", time.localtime())
192        ypos -= self.printVar(c, xcenter, ypos, _("Date"), datetime, 14, savetoner) 
193       
194        # Result of the print job
195        action = self.getVar("PYKOTAACTION")
196        if action == "ALLOW" :
197            action = _("Allowed")
198        elif action == "DENY" :   
199            action = _("Denied")
200        elif action == "WARN" :   
201            action = _("Allowed with Warning")
202        ypos -= self.printVar(c, xcenter, ypos, _("Result"), action, 14, savetoner) 
203       
204        # skip some space
205        ypos -= 20
206       
207        # Outputs title and filename
208        # We put them at x=0.25*pagewidth so that the line is long enough to hold them
209        title = self.getVar("PYKOTATITLE")
210        ypos -= self.printVar(c, xcenter / 2.0, ypos, _("Title"), title, 10, savetoner) 
211       
212        filename = self.getVar("PYKOTAFILENAME")
213        ypos -= self.printVar(c, xcenter / 2.0, ypos, _("Filename"), filename, 10, savetoner) 
214       
215        # skip some space
216        ypos -= 20
217       
218        # Now outputs the user's account balance or page counter
219        ypos -= self.printVar(c, xcenter, ypos, _("Pages printed so far on %s") % printername, self.getVar("PYKOTAPAGECOUNTER"), 14, savetoner) 
220        limitby = self.getVar("PYKOTALIMITBY")
221        if limitby == "balance" : 
222            ypos -= self.printVar(c, xcenter, ypos, _("Account balance"), self.getVar("PYKOTABALANCE"), 14, savetoner) 
223        else :
224            ypos -= self.printVar(c, xcenter, ypos, _("Soft Limit"), self.getVar("PYKOTASOFTLIMIT"), 14, savetoner) 
225            ypos -= self.printVar(c, xcenter, ypos, _("Hard Limit"), self.getVar("PYKOTAHARDLIMIT"), 14, savetoner) 
226            ypos -= self.printVar(c, xcenter, ypos, _("Date Limit"), self.getVar("PYKOTADATELIMIT"), 14, savetoner) 
227           
228        # URL
229        if url :
230            c.saveState()
231            c.setFont("Courier-Bold", 16)
232            (r, g, b) =  [ color + (savetoner * (1.0 - color)) for color in (0, 0, 1) ] # Blue * savetoner
233            c.setFillColorRGB(r, g, b)
234            c.drawCentredString(xcenter, 2 * cm, url)
235            c.restoreState()
236       
237        c.showPage()
238        c.save()
239        return document.getvalue()
240       
241    def main(self, files, options) :
242        """Generates a banner."""
243        if not hasRL :
244            raise PyKotaToolError, "The ReportLab module is missing. Download it from http://www.reportlab.org"
245        if not hasPIL :
246            raise PyKotaToolError, "The Python Imaging Library is missing. Download it from http://www.pythonware.com/downloads"
247           
248        try :
249            savetoner = int(options["savetoner"])
250            if (savetoner < 0) or (savetoner > 99) :
251                raise ValueError, _("Allowed range is (0..99)")
252            savetoner /= 100.0   
253        except (TypeError, ValueError), msg :
254            self.printInfo(_("Invalid 'savetoner' option %s : %s") % (options["savetoner"], msg), "warn")
255            savetoner = 0.0
256           
257        pagesize = self.getPageSize(options["pagesize"])
258        if pagesize is None :
259            pagesize = self.getPageSize("a4")
260            self.printInfo(_("Invalid 'pagesize' option %s, defaulting to A4.") % options["pagesize"], "warn")
261           
262        self.logdebug("Generating the banner in PDF format...")   
263        doc = self.genPDF(pagesize, options["logo"].strip(), options["url"].strip(), savetoner)
264       
265        self.logdebug("Converting the banner to PostScript...")   
266        os.environ["PATH"] = "%s:/bin:/usr/bin:/usr/local/bin:/opt/bin:/sbin:/usr/sbin" % os.environ.get("PATH", "")
267        child = popen2.Popen3("gs -q -dNOPAUSE -dBATCH -dPARANOIDSAFER -sDEVICE=pswrite -sOutputFile=- - 2>/tmp/errgs")
268        child.tochild.write(doc)
269        child.tochild.close()
270        sys.stdout.write(child.fromchild.read())
271        sys.stdout.flush()
272        child.fromchild.close()
273        status = child.wait()
274        if os.WIFEXITED(status) :
275            status = os.WEXITSTATUS(status)
276        self.logdebug("PDF to PostScript converter exit code is %s" % str(status))
277        self.logdebug("Banner completed.")
278        return status
279
280if __name__ == "__main__" :
281    # TODO : --papertray : to print banners on a different paper (colored for example)
282    retcode = 0
283    try :
284        defaults = { \
285                     "savetoner" : "0", \
286                     "pagesize" : "a4", \
287                     "logo" : "/usr/share/pykota/logos/pykota.jpeg",
288                     "url" : "http://www.librelogiciel.com/software/",
289                   }
290        short_options = "vhs:l:p:u:"
291        long_options = ["help", "version", "savetoner=", "pagesize=", "logo=", "url="]
292       
293        # Initializes the command line tool
294        banner = PyKotaBanner(doc=__doc__)
295       
296        # parse and checks the command line
297        (options, args) = banner.parseCommandline(sys.argv[1:], short_options, long_options, allownothing=1)
298       
299        # sets long options
300        options["help"] = options["h"] or options["help"]
301        options["version"] = options["v"] or options["version"]
302        options["savetoner"] = options["s"] or options["savetoner"] or defaults["savetoner"]
303        options["pagesize"] = options["p"] or options["pagesize"] or defaults["pagesize"]
304        options["url"] = options["u"] or options["url"] or defaults["url"]
305       
306        options["logo"] = options["l"] or options["logo"]
307        if options["logo"] is None : # Allows --logo="" to disable the logo entirely
308            options["logo"] = defaults["logo"] 
309       
310        if options["help"] :
311            banner.display_usage_and_quit()
312        elif options["version"] :
313            banner.display_version_and_quit()
314        else :
315            retcode = banner.main(args, options)
316    except SystemExit :       
317        pass
318    except :
319        try :
320            banner.crashed("pkbanner failed")
321        except :   
322            crashed("pkbanner failed")
323        retcode = -1
324       
325    sys.exit(retcode)   
Note: See TracBrowser for help on using the browser.