root / pykota / trunk / bin / pkbanner @ 1934

Revision 1934, 13.3 kB (checked in by jalet, 19 years ago)

Implemented the --savetoner command line option

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