root / pykota / trunk / bin / pkbanner @ 2065

Revision 2028, 14.0 kB (checked in by jalet, 20 years ago)

Modified copyright years

  • 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# $Log$
26# Revision 1.12  2005/01/17 08:44:23  jalet
27# Modified copyright years
28#
29# Revision 1.11  2004/12/03 12:34:28  jalet
30# Fixed the default value for the --savetoner command line option
31#
32# Revision 1.10  2004/11/17 13:28:19  jalet
33# Fixed some typo in the help
34#
35# Revision 1.9  2004/11/17 13:24:05  jalet
36# Improved pkbanner's help
37#
38# Revision 1.8  2004/11/17 13:12:04  jalet
39# Implemented the --savetoner command line option
40#
41# Revision 1.7  2004/11/15 22:29:01  jalet
42# Moved title and filename to the left to free some space.
43#
44# Revision 1.6  2004/11/15 22:20:27  jalet
45# Now outputs strings as-is, and not title-ized
46#
47# Revision 1.5  2004/11/15 22:01:34  jalet
48# Improved banner handling.
49# Fix for raw printing and banners.
50#
51# Revision 1.4  2004/11/15 19:59:34  jalet
52# PyKota banners now basically work !
53#
54# Revision 1.3  2004/11/12 23:46:44  jalet
55# Heavy work on pkbanner. Not finished yet though, but mostly works.
56#
57# Revision 1.2  2004/11/11 14:25:48  jalet
58# Added some TODO comments
59#
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
68import time
69import cStringIO
70import popen2
71
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
90__doc__ = N_("""pkbanner v%s (c) 2003, 2004, 2005 C@LL - Conseil Internet & Logiciels Libres
91
92Generates banners.
93
94command line usage :
95
96  pkbanner  [options]
97
98options :
99
100  -v | --version       Prints pkbanner's version number then exits.
101  -h | --help          Prints this message then exits.
102 
103  -l | --logo img      Use the image as the banner's logo. The logo will
104                       be drawn at the center top of the page. The default
105                       logo is /usr/share/pykota/logos/pykota.jpeg
106                       
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 
111  -s | --savetoner s   Sets the text luminosity factor to s%%. This can be
112                       used to save toner. The default value is 0, which
113                       means that no toner saving will be done.
114 
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 
119examples :                             
120
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 
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     
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               
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       
167    def printVar(self, canvas, x, y, label, value, size, savetoner) :
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)
174        (r, g, b) =  [ color + (savetoner * (1.0 - color)) for color in (0, 0, 0) ] # Black * savetoner
175        canvas.setFillColorRGB(r, g, b)
176        message = "%s :" % _(label)
177        canvas.drawRightString(x, y, message)
178        canvas.setFont("Courier-Bold", size)
179        (r, g, b) =  [ color + (savetoner * (1.0 - color)) for color in (1, 0, 0) ] # Red * savetoner
180        canvas.setFillColorRGB(r, g, b)
181        canvas.drawString(x + 0.5*cm, y, value)
182        canvas.restoreState()
183        return (size + 4)
184   
185    def genPDF(self, pagesize, logo, url, savetoner) :
186        """Generates the banner in PDF format, return the PDF document as a string."""
187       
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       
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       
214        # New top
215        xpos = pagesize[0] / 5.0
216        ypos -= (1 * cm) + 20
217       
218        printername = self.getVar("PYKOTAPRINTERNAME")
219        username = self.getVar("PYKOTAUSERNAME")
220        accountbanner = self.config.getAccountBanner(printername)
221       
222        # Outputs the username
223        ypos -= self.printVar(c, xcenter, ypos, _("Username"), username, 20, savetoner) 
224       
225        # Printer and Job Id
226        job = "%s - %s" % (printername, self.getVar("PYKOTAJOBID"))
227        ypos -= self.printVar(c, xcenter, ypos, _("Job"), job, 14, savetoner) 
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())
231        ypos -= self.printVar(c, xcenter, ypos, _("Date"), datetime, 14, savetoner) 
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")
241        ypos -= self.printVar(c, xcenter, ypos, _("Result"), action, 14, savetoner) 
242       
243        # skip some space
244        ypos -= 20
245       
246        # Outputs title and filename
247        # We put them at x=0.25*pagewidth so that the line is long enough to hold them
248        title = self.getVar("PYKOTATITLE")
249        ypos -= self.printVar(c, xcenter / 2.0, ypos, _("Title"), title, 10, savetoner) 
250       
251        filename = self.getVar("PYKOTAFILENAME")
252        ypos -= self.printVar(c, xcenter / 2.0, ypos, _("Filename"), filename, 10, savetoner) 
253       
254        # skip some space
255        ypos -= 20
256       
257        # Now outputs the user's account balance or page counter
258        ypos -= self.printVar(c, xcenter, ypos, _("Pages printed so far on %s") % printername, self.getVar("PYKOTAPAGECOUNTER"), 14, savetoner) 
259        limitby = self.getVar("PYKOTALIMITBY")
260        if limitby == "balance" : 
261            ypos -= self.printVar(c, xcenter, ypos, _("Account balance"), self.getVar("PYKOTABALANCE"), 14, savetoner) 
262        else :
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) 
266           
267        # URL
268        if url :
269            c.saveState()
270            c.setFont("Courier-Bold", 16)
271            (r, g, b) =  [ color + (savetoner * (1.0 - color)) for color in (0, 0, 1) ] # Blue * savetoner
272            c.setFillColorRGB(r, g, b)
273            c.drawCentredString(xcenter, 2 * cm, url)
274            c.restoreState()
275       
276        c.showPage()
277        c.save()
278        return document.getvalue()
279       
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           
287        try :
288            savetoner = int(options["savetoner"])
289            if (savetoner < 0) or (savetoner > 99) :
290                raise ValueError, _("Allowed range is (0..99)")
291            savetoner /= 100.0   
292        except (TypeError, ValueError), msg :
293            self.printInfo(_("Invalid 'savetoner' option %s : %s") % (options["savetoner"], msg), "warn")
294            savetoner = 0.0
295           
296        pagesize = self.getPageSize(options["pagesize"])
297        if pagesize is None :
298            pagesize = self.getPageSize("a4")
299            self.printInfo(_("Invalid 'pagesize' option %s, defaulting to A4.") % options["pagesize"], "warn")
300           
301        self.logdebug("Generating the banner in PDF format...")   
302        doc = self.genPDF(pagesize, options["logo"].strip(), options["url"].strip(), savetoner)
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
318
319if __name__ == "__main__" :
320    # TODO : --papertray : to print banners on a different paper (colored for example)
321    retcode = 0
322    try :
323        defaults = { \
324                     "savetoner" : "0", \
325                     "pagesize" : "a4", \
326                     "logo" : "/usr/share/pykota/logos/pykota.jpeg",
327                     "url" : "http://www.librelogiciel.com/software/",
328                   }
329        short_options = "vhs:l:p:u:"
330        long_options = ["help", "version", "savetoner=", "pagesize=", "logo=", "url="]
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"]
341        options["savetoner"] = options["s"] or options["savetoner"] or defaults["savetoner"]
342        options["pagesize"] = options["p"] or options["pagesize"] or defaults["pagesize"]
343        options["url"] = options["u"] or options["url"] or defaults["url"]
344       
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       
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.