root / pykota / trunk / bin / pkbanner @ 3305

Revision 3305, 12.2 kB (checked in by jerome, 16 years ago)

Now pkbanner uses the new command line parser. A bit rough around
the edges, and requires some refactoring, but it seems to work fine.

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
RevLine 
[1908]1#! /usr/bin/env python
[3260]2# -*- coding: UTF-8 -*-
[1908]3#
[3260]4# PyKota : Print Quotas for CUPS
[1908]5#
[3275]6# (c) 2003, 2004, 2005, 2006, 2007, 2008 Jerome Alet <alet@librelogiciel.com>
[3260]7# This program is free software: you can redistribute it and/or modify
[1908]8# it under the terms of the GNU General Public License as published by
[3260]9# the Free Software Foundation, either version 3 of the License, or
[1908]10# (at your option) any later version.
[3260]11#
[1908]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
[3260]18# along with this program.  If not, see <http://www.gnu.org/licenses/>.
[1908]19#
20# $Id$
21#
[2028]22#
[1908]23
[3305]24"""A banner generator for PyKota"""       
25
[1908]26import sys
27import os
[1923]28import time
[1911]29import cStringIO
[1918]30import popen2
[1908]31
[1911]32try :
33    from reportlab.pdfgen import canvas
34    from reportlab.lib import pagesizes
35    from reportlab.lib.units import cm
36except ImportError :   
[3288]37    hasRL = False
[1911]38else :   
[3288]39    hasRL = True
[1911]40   
41try :
42    import PIL.Image 
43except ImportError :   
[3288]44    hasPIL = False
[1911]45else :   
[3288]46    hasPIL = True
[1911]47   
[3294]48import pykota.appinit
49from pykota.utils import *
[3305]50from pykota.commandline import parser
[3294]51
[3288]52from pykota.errors import PyKotaToolError, PyKotaCommandLineError
[3295]53from pykota.tool import Tool
[3303]54from pykota import version
[1911]55
56class PyKotaBanner(Tool) :       
57    """A class for pkbanner."""
58    def getPageSize(self, pgsize) :
59        """Returns the correct page size or None if not found."""
60        try :
61            return getattr(pagesizes, pgsize.upper())
62        except AttributeError :   
63            try :
64                return getattr(pagesizes, pgsize.lower())
65            except AttributeError :
66                pass
67               
[1923]68    def getVar(self, varname) :           
69        """Extracts a variable from the environment and returns its value or 'Unknown' in the current locale."""
70        return os.environ.get(varname) or _("Unknown")
71       
[1934]72    def printVar(self, canvas, x, y, label, value, size, savetoner) :
[1923]73        """Outputs a variable onto the PDF canvas.
74       
75           Returns the number of points to substract to current Y coordinate.
76        """   
77        canvas.saveState()
78        canvas.setFont("Helvetica-Bold", size)
[1934]79        (r, g, b) =  [ color + (savetoner * (1.0 - color)) for color in (0, 0, 0) ] # Black * savetoner
[1923]80        canvas.setFillColorRGB(r, g, b)
[1925]81        message = "%s :" % _(label)
[3303]82        canvas.drawRightString(x, y, message)
[1923]83        canvas.setFont("Courier-Bold", size)
[1934]84        (r, g, b) =  [ color + (savetoner * (1.0 - color)) for color in (1, 0, 0) ] # Red * savetoner
[1923]85        canvas.setFillColorRGB(r, g, b)
[3303]86        canvas.drawString(x + 0.5*cm, y, value)
[1923]87        canvas.restoreState()
88        return (size + 4)
89   
[2193]90    def genPDF(self, pagesize, logo, url, text, savetoner) :
[1911]91        """Generates the banner in PDF format, return the PDF document as a string."""
92        document = cStringIO.StringIO()
93        c = canvas.Canvas(document, pagesize=pagesize, pageCompression=1)
94       
[3303]95        c.setAuthor(self.effectiveUserName)
96        c.setTitle(_("PyKota generated Banner"))
97        c.setSubject(_("This is a print banner generated with PyKota"))
[1911]98       
99        xcenter = pagesize[0] / 2.0
100        ycenter = pagesize[1] / 2.0
101                   
102        ypos = pagesize[1] - (2 * cm)           
103       
[1923]104        if logo :
105            try :   
106                imglogo = PIL.Image.open(logo)
107            except :   
108                self.printInfo("Unable to open image %s" % logo, "warn")
109            else :
110                (width, height) = imglogo.size
111                multi = float(width) / (8 * cm) 
112                width = float(width) / multi
113                height = float(height) / multi
114                xpos = xcenter - (width / 2.0)
115                ypos -= height
116                c.drawImage(logo, xpos, ypos, width, height)
117       
[1911]118        # New top
119        xpos = pagesize[0] / 5.0
120        ypos -= (1 * cm) + 20
121       
[1923]122        printername = self.getVar("PYKOTAPRINTERNAME")
123        username = self.getVar("PYKOTAUSERNAME")
124        accountbanner = self.config.getAccountBanner(printername)
125       
126        # Outputs the username
[1934]127        ypos -= self.printVar(c, xcenter, ypos, _("Username"), username, 20, savetoner) 
[1923]128       
[2193]129        # Text   
130        if text :
131            ypos -= self.printVar(c, xcenter, ypos, _("More Info"), text, 20, savetoner) 
132       
[1923]133        # Printer and Job Id
134        job = "%s - %s" % (printername, self.getVar("PYKOTAJOBID"))
[1934]135        ypos -= self.printVar(c, xcenter, ypos, _("Job"), job, 14, savetoner) 
[1923]136       
137        # Current date (TODO : at the time the banner was printed ! Change this to job's submission date)
138        datetime = time.strftime("%c", time.localtime())
[1934]139        ypos -= self.printVar(c, xcenter, ypos, _("Date"), datetime, 14, savetoner) 
[1923]140       
141        # Result of the print job
142        action = self.getVar("PYKOTAACTION")
143        if action == "ALLOW" :
144            action = _("Allowed")
145        elif action == "DENY" :   
146            action = _("Denied")
147        elif action == "WARN" :   
148            action = _("Allowed with Warning")
[2631]149        elif action == "PROBLEM" :   
150            # should never occur
151            action = _("Problem")
152        elif action == "CANCEL" :   
153            # should never occur
154            action = _("Cancelled")
[1934]155        ypos -= self.printVar(c, xcenter, ypos, _("Result"), action, 14, savetoner) 
[1923]156       
157        # skip some space
158        ypos -= 20
159       
160        # Outputs title and filename
[1926]161        # We put them at x=0.25*pagewidth so that the line is long enough to hold them
[1923]162        title = self.getVar("PYKOTATITLE")
[1934]163        ypos -= self.printVar(c, xcenter / 2.0, ypos, _("Title"), title, 10, savetoner) 
[1923]164       
165        filename = self.getVar("PYKOTAFILENAME")
[1934]166        ypos -= self.printVar(c, xcenter / 2.0, ypos, _("Filename"), filename, 10, savetoner) 
[1923]167       
168        # skip some space
169        ypos -= 20
170       
171        # Now outputs the user's account balance or page counter
[1934]172        ypos -= self.printVar(c, xcenter, ypos, _("Pages printed so far on %s") % printername, self.getVar("PYKOTAPAGECOUNTER"), 14, savetoner) 
[1923]173        limitby = self.getVar("PYKOTALIMITBY")
174        if limitby == "balance" : 
[1934]175            ypos -= self.printVar(c, xcenter, ypos, _("Account balance"), self.getVar("PYKOTABALANCE"), 14, savetoner) 
[2627]176        elif limitby == "quota" :
[1934]177            ypos -= self.printVar(c, xcenter, ypos, _("Soft Limit"), self.getVar("PYKOTASOFTLIMIT"), 14, savetoner) 
178            ypos -= self.printVar(c, xcenter, ypos, _("Hard Limit"), self.getVar("PYKOTAHARDLIMIT"), 14, savetoner) 
179            ypos -= self.printVar(c, xcenter, ypos, _("Date Limit"), self.getVar("PYKOTADATELIMIT"), 14, savetoner) 
[2627]180        else :
181            if limitby == "noquota" :
182                msg = _("No Limit")
183            elif limitby == "nochange" :   
184                msg = _("No Accounting")
185            elif limitby == "noprint" :   
186                msg = _("Forbidden")
187            else :   
188                msg = _("Unknown")
189            ypos -= self.printVar(c, xcenter, ypos, _("Printing Mode"), msg, 14, savetoner)
[1923]190           
191        # URL
192        if url :
[1911]193            c.saveState()
[1923]194            c.setFont("Courier-Bold", 16)
[1934]195            (r, g, b) =  [ color + (savetoner * (1.0 - color)) for color in (0, 0, 1) ] # Blue * savetoner
[1923]196            c.setFillColorRGB(r, g, b)
197            c.drawCentredString(xcenter, 2 * cm, url)
[1911]198            c.restoreState()
199       
200        c.showPage()
201        c.save()
202        return document.getvalue()
[1923]203       
[2193]204    def main(self, arguments, options) :
[1911]205        """Generates a banner."""
206        if not hasRL :
207            raise PyKotaToolError, "The ReportLab module is missing. Download it from http://www.reportlab.org"
208        if not hasPIL :
209            raise PyKotaToolError, "The Python Imaging Library is missing. Download it from http://www.pythonware.com/downloads"
210           
[1923]211        try :
[3305]212            if (options.savetoner < 0) or (options.savetoner > 99) :
[1934]213                raise ValueError, _("Allowed range is (0..99)")
[3305]214        except ValueError, msg :
215            self.printInfo(_("Invalid 'savetoner' option %s : %s") % (options.savetoner, msg), "warn")
[1934]216            savetoner = 0.0
[3305]217        else :   
218            savetoner = options.savetoner / 100.0   
[1923]219           
[3305]220        pagesize = self.getPageSize(options.pagesize)
[1911]221        if pagesize is None :
222            pagesize = self.getPageSize("a4")
[3305]223            self.printInfo(_("Invalid 'pagesize' option %s, defaulting to A4.") % options.pagesize, "warn")
[1911]224           
[1918]225        self.logdebug("Generating the banner in PDF format...")   
[2193]226        doc = self.genPDF(pagesize, 
[3305]227                          options.logo.strip().encode(sys.getfilesystemencoding(), "replace"), 
228                          options.url.strip(), 
[2193]229                          " ".join(arguments).strip(), 
230                          savetoner)
[1918]231       
232        self.logdebug("Converting the banner to PostScript...")   
233        os.environ["PATH"] = "%s:/bin:/usr/bin:/usr/local/bin:/opt/bin:/sbin:/usr/sbin" % os.environ.get("PATH", "")
[2193]234        child = popen2.Popen3("gs -q -dNOPAUSE -dBATCH -dPARANOIDSAFER -sDEVICE=pswrite -sOutputFile=- -")
235        try :
236            child.tochild.write(doc)
237            child.tochild.close()
238            sys.stdout.write(child.fromchild.read())
239            sys.stdout.flush()
240            child.fromchild.close()
241        except IOError, msg :   
242            self.printInfo("I/O Error %s" % msg, "error")
[1918]243        status = child.wait()
244        if os.WIFEXITED(status) :
245            status = os.WEXITSTATUS(status)
246        self.logdebug("PDF to PostScript converter exit code is %s" % str(status))
247        self.logdebug("Banner completed.")
248        return status
[1911]249
[1908]250if __name__ == "__main__" :
[1909]251    # TODO : --papertray : to print banners on a different paper (colored for example)
[3305]252    parser = parser.PyKotaOptionParser(description=_("Banner generator for PyKota"))
253    parser.add_option("-l", "--logo",
254                            dest="logo",
255                            default=u"/usr/share/pykota/logos/pykota.jpeg",
256                            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"))
257    parser.add_option("-p", "--pagesize",
258                            dest="pagesize",
259                            default=u"A4",
260                            help=_("Sets 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"))
261    parser.add_option("-s", "--savetoner",
262                            dest="savetoner",
263                            type="int",
264                            default=0,
265                            help=_("Sets 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."))
266    parser.add_option("-u", "--url",
267                            dest="url",
268                            default=u"http://www.pykota.com",
269                            help=_("Sets the url to write at the bottom of the banner page. The default url is %default"))
270    parser.add_example('--logo="" --savetoner=75',
271                       _("This would generate an A4 banner with no logo, and text luminosity would be increased by 75%%."))
272    (options, arguments) = parser.parse_args()                   
273    if options.version :
274        from pykota import version
275        sys.stdout.write("%s\n" % version.__version__)
276        sys.exit(0)
277   
[1911]278    retcode = 0
279    try :
280        # Initializes the command line tool
[3305]281        banner = PyKotaBanner()
[2210]282        banner.deferredInit()
[3305]283        retcode = banner.main(arguments, options)
[2216]284    except KeyboardInterrupt :       
[3294]285        logerr("\nInterrupted with Ctrl+C !\n")
[2609]286        retcode = -3
[2512]287    except PyKotaCommandLineError, msg :   
[3294]288        logerr("%s : %s\n" % (sys.argv[0], msg))
[2609]289        retcode = -2
[1911]290    except SystemExit :       
291        pass
292    except :
293        try :
294            banner.crashed("pkbanner failed")
295        except :   
296            crashed("pkbanner failed")
297        retcode = -1
298       
299    sys.exit(retcode)   
Note: See TracBrowser for help on using the browser.