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
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
[3319]30import subprocess
[1908]31
[1911]32try :
33    from reportlab.pdfgen import canvas
[3319]34    import reportlab.lib
[1911]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
[3335]49from pykota.utils import run
50from pykota.commandline import PyKotaOptionParser, \
51                               checkandset_pagesize, \
52                               checkandset_savetoner
53from pykota.pdfutils import getPageSize
[3319]54from pykota.errors import PyKotaToolError
[3295]55from pykota.tool import Tool
[3303]56from pykota import version
[1911]57
[3319]58class PyKotaBanner(Tool) :       
59    """A class for pkbanner."""
[1923]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       
[1934]64    def printVar(self, canvas, x, y, label, value, size, savetoner) :
[1923]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)
[1934]71        (r, g, b) =  [ color + (savetoner * (1.0 - color)) for color in (0, 0, 0) ] # Black * savetoner
[1923]72        canvas.setFillColorRGB(r, g, b)
[1925]73        message = "%s :" % _(label)
[3303]74        canvas.drawRightString(x, y, message)
[1923]75        canvas.setFont("Courier-Bold", size)
[1934]76        (r, g, b) =  [ color + (savetoner * (1.0 - color)) for color in (1, 0, 0) ] # Red * savetoner
[1923]77        canvas.setFillColorRGB(r, g, b)
[3303]78        canvas.drawString(x + 0.5*cm, y, value)
[1923]79        canvas.restoreState()
80        return (size + 4)
81   
[2193]82    def genPDF(self, pagesize, logo, url, text, savetoner) :
[1911]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       
[3303]87        c.setAuthor(self.effectiveUserName)
88        c.setTitle(_("PyKota generated Banner"))
89        c.setSubject(_("This is a print banner generated with PyKota"))
[1911]90       
91        xcenter = pagesize[0] / 2.0
92        ycenter = pagesize[1] / 2.0
93                   
94        ypos = pagesize[1] - (2 * cm)           
95       
[1923]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       
[1911]110        # New top
111        xpos = pagesize[0] / 5.0
112        ypos -= (1 * cm) + 20
113       
[1923]114        printername = self.getVar("PYKOTAPRINTERNAME")
115        username = self.getVar("PYKOTAUSERNAME")
116        accountbanner = self.config.getAccountBanner(printername)
117       
118        # Outputs the username
[1934]119        ypos -= self.printVar(c, xcenter, ypos, _("Username"), username, 20, savetoner) 
[1923]120       
[2193]121        # Text   
122        if text :
123            ypos -= self.printVar(c, xcenter, ypos, _("More Info"), text, 20, savetoner) 
124       
[1923]125        # Printer and Job Id
126        job = "%s - %s" % (printername, self.getVar("PYKOTAJOBID"))
[1934]127        ypos -= self.printVar(c, xcenter, ypos, _("Job"), job, 14, savetoner) 
[1923]128       
129        # Current date (TODO : at the time the banner was printed ! Change this to job's submission date)
[3319]130        datetime = time.strftime("%c", time.localtime()).decode(self.charset, "replace")
[1934]131        ypos -= self.printVar(c, xcenter, ypos, _("Date"), datetime, 14, savetoner) 
[1923]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")
[2631]141        elif action == "PROBLEM" :   
142            # should never occur
143            action = _("Problem")
144        elif action == "CANCEL" :   
145            # should never occur
146            action = _("Cancelled")
[1934]147        ypos -= self.printVar(c, xcenter, ypos, _("Result"), action, 14, savetoner) 
[1923]148       
149        # skip some space
150        ypos -= 20
151       
152        # Outputs title and filename
[1926]153        # We put them at x=0.25*pagewidth so that the line is long enough to hold them
[1923]154        title = self.getVar("PYKOTATITLE")
[1934]155        ypos -= self.printVar(c, xcenter / 2.0, ypos, _("Title"), title, 10, savetoner) 
[1923]156       
157        filename = self.getVar("PYKOTAFILENAME")
[1934]158        ypos -= self.printVar(c, xcenter / 2.0, ypos, _("Filename"), filename, 10, savetoner) 
[1923]159       
160        # skip some space
161        ypos -= 20
162       
163        # Now outputs the user's account balance or page counter
[1934]164        ypos -= self.printVar(c, xcenter, ypos, _("Pages printed so far on %s") % printername, self.getVar("PYKOTAPAGECOUNTER"), 14, savetoner) 
[1923]165        limitby = self.getVar("PYKOTALIMITBY")
166        if limitby == "balance" : 
[1934]167            ypos -= self.printVar(c, xcenter, ypos, _("Account balance"), self.getVar("PYKOTABALANCE"), 14, savetoner) 
[2627]168        elif limitby == "quota" :
[1934]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) 
[2627]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)
[1923]182           
183        # URL
184        if url :
[1911]185            c.saveState()
[1923]186            c.setFont("Courier-Bold", 16)
[1934]187            (r, g, b) =  [ color + (savetoner * (1.0 - color)) for color in (0, 0, 1) ] # Blue * savetoner
[1923]188            c.setFillColorRGB(r, g, b)
189            c.drawCentredString(xcenter, 2 * cm, url)
[1911]190            c.restoreState()
191       
192        c.showPage()
193        c.save()
194        return document.getvalue()
[1923]195       
[2193]196    def main(self, arguments, options) :
[1911]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           
[1918]203        self.logdebug("Generating the banner in PDF format...")   
[3319]204        doc = self.genPDF(getPageSize(options.pagesize),
[3305]205                          options.logo.strip().encode(sys.getfilesystemencoding(), "replace"), 
206                          options.url.strip(), 
[2193]207                          " ".join(arguments).strip(), 
[3332]208                          options.savetoner / 100.0)
[1918]209       
210        self.logdebug("Converting the banner to PostScript...")   
[3319]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()
[1918]222        if os.WIFEXITED(status) :
223            status = os.WEXITSTATUS(status)
224        self.logdebug("PDF to PostScript converter exit code is %s" % str(status))
[3319]225        sys.stdout.write(out)
226        sys.stdout.flush()
[1918]227        self.logdebug("Banner completed.")
228        return status
[1911]229
[1908]230if __name__ == "__main__" :
[1909]231    # TODO : --papertray : to print banners on a different paper (colored for example)
[3326]232    parser = PyKotaOptionParser(description=_("Banner generator for PyKota."))
[3305]233    parser.add_option("-l", "--logo",
234                            dest="logo",
235                            default=u"/usr/share/pykota/logos/pykota.jpeg",
[3337]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"))
[3305]237    parser.add_option("-p", "--pagesize",
[3319]238                            type="string",
239                            action="callback",
240                            callback=checkandset_pagesize,
[3305]241                            dest="pagesize",
242                            default=u"A4",
[3325]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"))
[3305]244    parser.add_option("-s", "--savetoner",
[3319]245                            type="float",
246                            action="callback",
247                            callback=checkandset_savetoner,
[3305]248                            dest="savetoner",
[3319]249                            default=0.0,
[3325]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."))
[3305]251    parser.add_option("-u", "--url",
252                            dest="url",
253                            default=u"http://www.pykota.com",
[3325]254                            help=_("Set the url to write at the bottom of the banner page. The default url is %default"))
[3305]255    parser.add_example('--logo="" --savetoner=75',
[3319]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.