root / pykota / trunk / bin / pkbanner @ 3337

Revision 3337, 11.0 kB (checked in by jerome, 16 years ago)

Added some utility methods.
Made generic --logo help not depend anymore on the pkbanner's
command context.

  • 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: UTF-8 -*-
3#
4# PyKota : Print Quotas for CUPS
5#
6# (c) 2003, 2004, 2005, 2006, 2007, 2008 Jerome Alet <alet@librelogiciel.com>
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation, either version 3 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program.  If not, see <http://www.gnu.org/licenses/>.
19#
20# $Id$
21#
22#
23
24"""A banner generator for PyKota"""       
25
26import sys
27import os
28import time
29import cStringIO
30import subprocess
31
32try :
33    from reportlab.pdfgen import canvas
34    import reportlab.lib
35    from reportlab.lib.units import cm
36except ImportError :   
37    hasRL = False
38else :   
39    hasRL = True
40   
41try :
42    import PIL.Image 
43except ImportError :   
44    hasPIL = False
45else :   
46    hasPIL = True
47   
48import pykota.appinit
49from pykota.utils import run
50from pykota.commandline import PyKotaOptionParser, \
51                               checkandset_pagesize, \
52                               checkandset_savetoner
53from pykota.pdfutils import getPageSize
54from pykota.errors import PyKotaToolError
55from pykota.tool import Tool
56from pykota import version
57
58class PyKotaBanner(Tool) :       
59    """A class for pkbanner."""
60    def getVar(self, varname) :           
61        """Extracts a variable from the environment and returns its value or 'Unknown' in the current locale."""
62        return os.environ.get(varname) or _("Unknown")
63       
64    def printVar(self, canvas, x, y, label, value, size, savetoner) :
65        """Outputs a variable onto the PDF canvas.
66       
67           Returns the number of points to substract to current Y coordinate.
68        """   
69        canvas.saveState()
70        canvas.setFont("Helvetica-Bold", size)
71        (r, g, b) =  [ color + (savetoner * (1.0 - color)) for color in (0, 0, 0) ] # Black * savetoner
72        canvas.setFillColorRGB(r, g, b)
73        message = "%s :" % _(label)
74        canvas.drawRightString(x, y, message)
75        canvas.setFont("Courier-Bold", size)
76        (r, g, b) =  [ color + (savetoner * (1.0 - color)) for color in (1, 0, 0) ] # Red * savetoner
77        canvas.setFillColorRGB(r, g, b)
78        canvas.drawString(x + 0.5*cm, y, value)
79        canvas.restoreState()
80        return (size + 4)
81   
82    def genPDF(self, pagesize, logo, url, text, savetoner) :
83        """Generates the banner in PDF format, return the PDF document as a string."""
84        document = cStringIO.StringIO()
85        c = canvas.Canvas(document, pagesize=pagesize, pageCompression=1)
86       
87        c.setAuthor(self.effectiveUserName)
88        c.setTitle(_("PyKota generated Banner"))
89        c.setSubject(_("This is a print banner generated with PyKota"))
90       
91        xcenter = pagesize[0] / 2.0
92        ycenter = pagesize[1] / 2.0
93                   
94        ypos = pagesize[1] - (2 * cm)           
95       
96        if logo :
97            try :   
98                imglogo = PIL.Image.open(logo)
99            except :   
100                self.printInfo("Unable to open image %s" % logo, "warn")
101            else :
102                (width, height) = imglogo.size
103                multi = float(width) / (8 * cm) 
104                width = float(width) / multi
105                height = float(height) / multi
106                xpos = xcenter - (width / 2.0)
107                ypos -= height
108                c.drawImage(logo, xpos, ypos, width, height)
109       
110        # New top
111        xpos = pagesize[0] / 5.0
112        ypos -= (1 * cm) + 20
113       
114        printername = self.getVar("PYKOTAPRINTERNAME")
115        username = self.getVar("PYKOTAUSERNAME")
116        accountbanner = self.config.getAccountBanner(printername)
117       
118        # Outputs the username
119        ypos -= self.printVar(c, xcenter, ypos, _("Username"), username, 20, savetoner) 
120       
121        # Text   
122        if text :
123            ypos -= self.printVar(c, xcenter, ypos, _("More Info"), text, 20, savetoner) 
124       
125        # Printer and Job Id
126        job = "%s - %s" % (printername, self.getVar("PYKOTAJOBID"))
127        ypos -= self.printVar(c, xcenter, ypos, _("Job"), job, 14, savetoner) 
128       
129        # Current date (TODO : at the time the banner was printed ! Change this to job's submission date)
130        datetime = time.strftime("%c", time.localtime()).decode(self.charset, "replace")
131        ypos -= self.printVar(c, xcenter, ypos, _("Date"), datetime, 14, savetoner) 
132       
133        # Result of the print job
134        action = self.getVar("PYKOTAACTION")
135        if action == "ALLOW" :
136            action = _("Allowed")
137        elif action == "DENY" :   
138            action = _("Denied")
139        elif action == "WARN" :   
140            action = _("Allowed with Warning")
141        elif action == "PROBLEM" :   
142            # should never occur
143            action = _("Problem")
144        elif action == "CANCEL" :   
145            # should never occur
146            action = _("Cancelled")
147        ypos -= self.printVar(c, xcenter, ypos, _("Result"), action, 14, savetoner) 
148       
149        # skip some space
150        ypos -= 20
151       
152        # Outputs title and filename
153        # We put them at x=0.25*pagewidth so that the line is long enough to hold them
154        title = self.getVar("PYKOTATITLE")
155        ypos -= self.printVar(c, xcenter / 2.0, ypos, _("Title"), title, 10, savetoner) 
156       
157        filename = self.getVar("PYKOTAFILENAME")
158        ypos -= self.printVar(c, xcenter / 2.0, ypos, _("Filename"), filename, 10, savetoner) 
159       
160        # skip some space
161        ypos -= 20
162       
163        # Now outputs the user's account balance or page counter
164        ypos -= self.printVar(c, xcenter, ypos, _("Pages printed so far on %s") % printername, self.getVar("PYKOTAPAGECOUNTER"), 14, savetoner) 
165        limitby = self.getVar("PYKOTALIMITBY")
166        if limitby == "balance" : 
167            ypos -= self.printVar(c, xcenter, ypos, _("Account balance"), self.getVar("PYKOTABALANCE"), 14, savetoner) 
168        elif limitby == "quota" :
169            ypos -= self.printVar(c, xcenter, ypos, _("Soft Limit"), self.getVar("PYKOTASOFTLIMIT"), 14, savetoner) 
170            ypos -= self.printVar(c, xcenter, ypos, _("Hard Limit"), self.getVar("PYKOTAHARDLIMIT"), 14, savetoner) 
171            ypos -= self.printVar(c, xcenter, ypos, _("Date Limit"), self.getVar("PYKOTADATELIMIT"), 14, savetoner) 
172        else :
173            if limitby == "noquota" :
174                msg = _("No Limit")
175            elif limitby == "nochange" :   
176                msg = _("No Accounting")
177            elif limitby == "noprint" :   
178                msg = _("Forbidden")
179            else :   
180                msg = _("Unknown")
181            ypos -= self.printVar(c, xcenter, ypos, _("Printing Mode"), msg, 14, savetoner)
182           
183        # URL
184        if url :
185            c.saveState()
186            c.setFont("Courier-Bold", 16)
187            (r, g, b) =  [ color + (savetoner * (1.0 - color)) for color in (0, 0, 1) ] # Blue * savetoner
188            c.setFillColorRGB(r, g, b)
189            c.drawCentredString(xcenter, 2 * cm, url)
190            c.restoreState()
191       
192        c.showPage()
193        c.save()
194        return document.getvalue()
195       
196    def main(self, arguments, options) :
197        """Generates a banner."""
198        if not hasRL :
199            raise PyKotaToolError, "The ReportLab module is missing. Download it from http://www.reportlab.org"
200        if not hasPIL :
201            raise PyKotaToolError, "The Python Imaging Library is missing. Download it from http://www.pythonware.com/downloads"
202           
203        self.logdebug("Generating the banner in PDF format...")   
204        doc = self.genPDF(getPageSize(options.pagesize),
205                          options.logo.strip().encode(sys.getfilesystemencoding(), "replace"), 
206                          options.url.strip(), 
207                          " ".join(arguments).strip(), 
208                          options.savetoner / 100.0)
209       
210        self.logdebug("Converting the banner to PostScript...")   
211        command = "gs -q -dNOPAUSE -dBATCH -dPARANOIDSAFER -sDEVICE=pswrite -sOutputFile=- -"
212        subpr = subprocess.Popen(command,
213                                 shell=True,
214                                 stdin=subprocess.PIPE,
215                                 stdout=subprocess.PIPE,
216                                 stderr=subprocess.PIPE)
217        try :                         
218            (out, err) = subpr.communicate(doc)
219        except OSError, msg :   
220            raise PyKotaToolError, _("Impossible to execute '%(command)s'") % locals()
221        status = subpr.wait()
222        if os.WIFEXITED(status) :
223            status = os.WEXITSTATUS(status)
224        self.logdebug("PDF to PostScript converter exit code is %s" % str(status))
225        sys.stdout.write(out)
226        sys.stdout.flush()
227        self.logdebug("Banner completed.")
228        return status
229
230if __name__ == "__main__" :
231    # TODO : --papertray : to print banners on a different paper (colored for example)
232    parser = PyKotaOptionParser(description=_("Banner generator for PyKota."))
233    parser.add_option("-l", "--logo",
234                            dest="logo",
235                            default=u"/usr/share/pykota/logos/pykota.jpeg",
236                            help=_("The image to use as a logo. The logo will be drawn at the center top of the page. The default logo is %default"))
237    parser.add_option("-p", "--pagesize",
238                            type="string",
239                            action="callback",
240                            callback=checkandset_pagesize,
241                            dest="pagesize",
242                            default=u"A4",
243                            help=_("Set the size of the page. Most well known page sizes are recognized, like 'A4' or 'Letter' to name a few. The default page size is %default"))
244    parser.add_option("-s", "--savetoner",
245                            type="float",
246                            action="callback",
247                            callback=checkandset_savetoner,
248                            dest="savetoner",
249                            default=0.0,
250                            help=_("Set the text luminosity to this percent. This can be used to save toner. The default value is %default, which means that no toner saving will be done."))
251    parser.add_option("-u", "--url",
252                            dest="url",
253                            default=u"http://www.pykota.com",
254                            help=_("Set the url to write at the bottom of the banner page. The default url is %default"))
255    parser.add_example('--logo="" --savetoner=75',
256                       _("This would generate a banner in the default page size, with no logo, and text luminosity would be increased by 75%."))
257                       
258    run(parser, PyKotaBanner)
Note: See TracBrowser for help on using the browser.