root / pykota / trunk / bin / pkbanner @ 3330

Revision 3330, 12.1 kB (checked in by jerome, 16 years ago)

Reduced the scope of some import statements.
Fixed some minor problems.
Fixed a bug in pykosd where the --color command line option was used.

  • 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, loginvalidparam
50from pykota.commandline import PyKotaOptionParser
51
52from pykota.errors import PyKotaToolError
53from pykota.tool import Tool
54from pykota import version
55
56def getPageSize(pgsize) :
57    """Returns the correct page size or None if not found."""
58    try :
59        try :
60            return getattr(reportlab.lib.pagesizes, pgsize.upper())
61        except AttributeError :   
62            try :
63                return getattr(reportlab.lib.pagesizes, pgsize.lower())
64            except AttributeError :
65                pass
66    except UnicodeError :           
67        pass
68    return None       
69   
70class PyKotaBanner(Tool) :       
71    """A class for pkbanner."""
72    def getVar(self, varname) :           
73        """Extracts a variable from the environment and returns its value or 'Unknown' in the current locale."""
74        return os.environ.get(varname) or _("Unknown")
75       
76    def printVar(self, canvas, x, y, label, value, size, savetoner) :
77        """Outputs a variable onto the PDF canvas.
78       
79           Returns the number of points to substract to current Y coordinate.
80        """   
81        canvas.saveState()
82        canvas.setFont("Helvetica-Bold", size)
83        (r, g, b) =  [ color + (savetoner * (1.0 - color)) for color in (0, 0, 0) ] # Black * savetoner
84        canvas.setFillColorRGB(r, g, b)
85        message = "%s :" % _(label)
86        canvas.drawRightString(x, y, message)
87        canvas.setFont("Courier-Bold", size)
88        (r, g, b) =  [ color + (savetoner * (1.0 - color)) for color in (1, 0, 0) ] # Red * savetoner
89        canvas.setFillColorRGB(r, g, b)
90        canvas.drawString(x + 0.5*cm, y, value)
91        canvas.restoreState()
92        return (size + 4)
93   
94    def genPDF(self, pagesize, logo, url, text, savetoner) :
95        """Generates the banner in PDF format, return the PDF document as a string."""
96        document = cStringIO.StringIO()
97        c = canvas.Canvas(document, pagesize=pagesize, pageCompression=1)
98       
99        c.setAuthor(self.effectiveUserName)
100        c.setTitle(_("PyKota generated Banner"))
101        c.setSubject(_("This is a print banner generated with PyKota"))
102       
103        xcenter = pagesize[0] / 2.0
104        ycenter = pagesize[1] / 2.0
105                   
106        ypos = pagesize[1] - (2 * cm)           
107       
108        if logo :
109            try :   
110                imglogo = PIL.Image.open(logo)
111            except :   
112                self.printInfo("Unable to open image %s" % logo, "warn")
113            else :
114                (width, height) = imglogo.size
115                multi = float(width) / (8 * cm) 
116                width = float(width) / multi
117                height = float(height) / multi
118                xpos = xcenter - (width / 2.0)
119                ypos -= height
120                c.drawImage(logo, xpos, ypos, width, height)
121       
122        # New top
123        xpos = pagesize[0] / 5.0
124        ypos -= (1 * cm) + 20
125       
126        printername = self.getVar("PYKOTAPRINTERNAME")
127        username = self.getVar("PYKOTAUSERNAME")
128        accountbanner = self.config.getAccountBanner(printername)
129       
130        # Outputs the username
131        ypos -= self.printVar(c, xcenter, ypos, _("Username"), username, 20, savetoner) 
132       
133        # Text   
134        if text :
135            ypos -= self.printVar(c, xcenter, ypos, _("More Info"), text, 20, savetoner) 
136       
137        # Printer and Job Id
138        job = "%s - %s" % (printername, self.getVar("PYKOTAJOBID"))
139        ypos -= self.printVar(c, xcenter, ypos, _("Job"), job, 14, savetoner) 
140       
141        # Current date (TODO : at the time the banner was printed ! Change this to job's submission date)
142        datetime = time.strftime("%c", time.localtime()).decode(self.charset, "replace")
143        ypos -= self.printVar(c, xcenter, ypos, _("Date"), datetime, 14, savetoner) 
144       
145        # Result of the print job
146        action = self.getVar("PYKOTAACTION")
147        if action == "ALLOW" :
148            action = _("Allowed")
149        elif action == "DENY" :   
150            action = _("Denied")
151        elif action == "WARN" :   
152            action = _("Allowed with Warning")
153        elif action == "PROBLEM" :   
154            # should never occur
155            action = _("Problem")
156        elif action == "CANCEL" :   
157            # should never occur
158            action = _("Cancelled")
159        ypos -= self.printVar(c, xcenter, ypos, _("Result"), action, 14, savetoner) 
160       
161        # skip some space
162        ypos -= 20
163       
164        # Outputs title and filename
165        # We put them at x=0.25*pagewidth so that the line is long enough to hold them
166        title = self.getVar("PYKOTATITLE")
167        ypos -= self.printVar(c, xcenter / 2.0, ypos, _("Title"), title, 10, savetoner) 
168       
169        filename = self.getVar("PYKOTAFILENAME")
170        ypos -= self.printVar(c, xcenter / 2.0, ypos, _("Filename"), filename, 10, savetoner) 
171       
172        # skip some space
173        ypos -= 20
174       
175        # Now outputs the user's account balance or page counter
176        ypos -= self.printVar(c, xcenter, ypos, _("Pages printed so far on %s") % printername, self.getVar("PYKOTAPAGECOUNTER"), 14, savetoner) 
177        limitby = self.getVar("PYKOTALIMITBY")
178        if limitby == "balance" : 
179            ypos -= self.printVar(c, xcenter, ypos, _("Account balance"), self.getVar("PYKOTABALANCE"), 14, savetoner) 
180        elif limitby == "quota" :
181            ypos -= self.printVar(c, xcenter, ypos, _("Soft Limit"), self.getVar("PYKOTASOFTLIMIT"), 14, savetoner) 
182            ypos -= self.printVar(c, xcenter, ypos, _("Hard Limit"), self.getVar("PYKOTAHARDLIMIT"), 14, savetoner) 
183            ypos -= self.printVar(c, xcenter, ypos, _("Date Limit"), self.getVar("PYKOTADATELIMIT"), 14, savetoner) 
184        else :
185            if limitby == "noquota" :
186                msg = _("No Limit")
187            elif limitby == "nochange" :   
188                msg = _("No Accounting")
189            elif limitby == "noprint" :   
190                msg = _("Forbidden")
191            else :   
192                msg = _("Unknown")
193            ypos -= self.printVar(c, xcenter, ypos, _("Printing Mode"), msg, 14, savetoner)
194           
195        # URL
196        if url :
197            c.saveState()
198            c.setFont("Courier-Bold", 16)
199            (r, g, b) =  [ color + (savetoner * (1.0 - color)) for color in (0, 0, 1) ] # Blue * savetoner
200            c.setFillColorRGB(r, g, b)
201            c.drawCentredString(xcenter, 2 * cm, url)
202            c.restoreState()
203       
204        c.showPage()
205        c.save()
206        return document.getvalue()
207       
208    def main(self, arguments, options) :
209        """Generates a banner."""
210        if not hasRL :
211            raise PyKotaToolError, "The ReportLab module is missing. Download it from http://www.reportlab.org"
212        if not hasPIL :
213            raise PyKotaToolError, "The Python Imaging Library is missing. Download it from http://www.pythonware.com/downloads"
214           
215        self.logdebug("Generating the banner in PDF format...")   
216        doc = self.genPDF(getPageSize(options.pagesize),
217                          options.logo.strip().encode(sys.getfilesystemencoding(), "replace"), 
218                          options.url.strip(), 
219                          " ".join(arguments).strip(), 
220                          options.savetoner)
221       
222        self.logdebug("Converting the banner to PostScript...")   
223        command = "gs -q -dNOPAUSE -dBATCH -dPARANOIDSAFER -sDEVICE=pswrite -sOutputFile=- -"
224        subpr = subprocess.Popen(command,
225                                 shell=True,
226                                 stdin=subprocess.PIPE,
227                                 stdout=subprocess.PIPE,
228                                 stderr=subprocess.PIPE)
229        try :                         
230            (out, err) = subpr.communicate(doc)
231        except OSError, msg :   
232            raise PyKotaToolError, _("Impossible to execute '%(command)s'") % locals()
233        status = subpr.wait()
234        if os.WIFEXITED(status) :
235            status = os.WEXITSTATUS(status)
236        self.logdebug("PDF to PostScript converter exit code is %s" % str(status))
237        sys.stdout.write(out)
238        sys.stdout.flush()
239        self.logdebug("Banner completed.")
240        return status
241
242if __name__ == "__main__" :
243    def checkandset_pagesize(option, opt, value, optionparser) :
244        """Checks and sets the page size."""
245        if getPageSize(value) is None :
246            loginvalidparam(opt, value, option.default)
247            setattr(optionparser.values, option.dest, option.default)
248        else :   
249            setattr(optionparser.values, option.dest, value)
250       
251    def checkandset_savetoner(option, opt, value, optionparser) :   
252        """Checks and sets the save toner value."""
253        if (value < 0.0) or (value > 99.0) :
254            loginvalidparam(opt, value, option.default, \
255                            _("Allowed range is (0..99)"))
256            setattr(optionparser.values, option.dest, option.default)
257        else :   
258            setattr(optionparser.values, option.dest, value / 100.0)
259       
260    # TODO : --papertray : to print banners on a different paper (colored for example)
261    parser = PyKotaOptionParser(description=_("Banner generator for PyKota."))
262    parser.add_option("-l", "--logo",
263                            dest="logo",
264                            default=u"/usr/share/pykota/logos/pykota.jpeg",
265                            help=_("The image to use as the banner's logo. The logo will be drawn at the center top of the page. The default logo is %default"))
266    parser.add_option("-p", "--pagesize",
267                            type="string",
268                            action="callback",
269                            callback=checkandset_pagesize,
270                            dest="pagesize",
271                            default=u"A4",
272                            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"))
273    parser.add_option("-s", "--savetoner",
274                            type="float",
275                            action="callback",
276                            callback=checkandset_savetoner,
277                            dest="savetoner",
278                            default=0.0,
279                            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."))
280    parser.add_option("-u", "--url",
281                            dest="url",
282                            default=u"http://www.pykota.com",
283                            help=_("Set the url to write at the bottom of the banner page. The default url is %default"))
284    parser.add_example('--logo="" --savetoner=75',
285                       _("This would generate a banner in the default page size, with no logo, and text luminosity would be increased by 75%."))
286                       
287    run(parser, PyKotaBanner)
Note: See TracBrowser for help on using the browser.