root / pykota / trunk / bin / pkbanner @ 3331

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

Minor fix, just in case the default value is not 0 anymore.

  • 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
[3330]49from pykota.utils import run, loginvalidparam
[3320]50from pykota.commandline import PyKotaOptionParser
[3294]51
[3319]52from pykota.errors import PyKotaToolError
[3295]53from pykota.tool import Tool
[3303]54from pykota import version
[1911]55
[3319]56def getPageSize(pgsize) :
57    """Returns the correct page size or None if not found."""
58    try :
[1911]59        try :
[3319]60            return getattr(reportlab.lib.pagesizes, pgsize.upper())
[1911]61        except AttributeError :   
62            try :
[3319]63                return getattr(reportlab.lib.pagesizes, pgsize.lower())
[1911]64            except AttributeError :
65                pass
[3319]66    except UnicodeError :           
67        pass
68    return None       
69   
70class PyKotaBanner(Tool) :       
71    """A class for pkbanner."""
[1923]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       
[1934]76    def printVar(self, canvas, x, y, label, value, size, savetoner) :
[1923]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)
[1934]83        (r, g, b) =  [ color + (savetoner * (1.0 - color)) for color in (0, 0, 0) ] # Black * savetoner
[1923]84        canvas.setFillColorRGB(r, g, b)
[1925]85        message = "%s :" % _(label)
[3303]86        canvas.drawRightString(x, y, message)
[1923]87        canvas.setFont("Courier-Bold", size)
[1934]88        (r, g, b) =  [ color + (savetoner * (1.0 - color)) for color in (1, 0, 0) ] # Red * savetoner
[1923]89        canvas.setFillColorRGB(r, g, b)
[3303]90        canvas.drawString(x + 0.5*cm, y, value)
[1923]91        canvas.restoreState()
92        return (size + 4)
93   
[2193]94    def genPDF(self, pagesize, logo, url, text, savetoner) :
[1911]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       
[3303]99        c.setAuthor(self.effectiveUserName)
100        c.setTitle(_("PyKota generated Banner"))
101        c.setSubject(_("This is a print banner generated with PyKota"))
[1911]102       
103        xcenter = pagesize[0] / 2.0
104        ycenter = pagesize[1] / 2.0
105                   
106        ypos = pagesize[1] - (2 * cm)           
107       
[1923]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       
[1911]122        # New top
123        xpos = pagesize[0] / 5.0
124        ypos -= (1 * cm) + 20
125       
[1923]126        printername = self.getVar("PYKOTAPRINTERNAME")
127        username = self.getVar("PYKOTAUSERNAME")
128        accountbanner = self.config.getAccountBanner(printername)
129       
130        # Outputs the username
[1934]131        ypos -= self.printVar(c, xcenter, ypos, _("Username"), username, 20, savetoner) 
[1923]132       
[2193]133        # Text   
134        if text :
135            ypos -= self.printVar(c, xcenter, ypos, _("More Info"), text, 20, savetoner) 
136       
[1923]137        # Printer and Job Id
138        job = "%s - %s" % (printername, self.getVar("PYKOTAJOBID"))
[1934]139        ypos -= self.printVar(c, xcenter, ypos, _("Job"), job, 14, savetoner) 
[1923]140       
141        # Current date (TODO : at the time the banner was printed ! Change this to job's submission date)
[3319]142        datetime = time.strftime("%c", time.localtime()).decode(self.charset, "replace")
[1934]143        ypos -= self.printVar(c, xcenter, ypos, _("Date"), datetime, 14, savetoner) 
[1923]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")
[2631]153        elif action == "PROBLEM" :   
154            # should never occur
155            action = _("Problem")
156        elif action == "CANCEL" :   
157            # should never occur
158            action = _("Cancelled")
[1934]159        ypos -= self.printVar(c, xcenter, ypos, _("Result"), action, 14, savetoner) 
[1923]160       
161        # skip some space
162        ypos -= 20
163       
164        # Outputs title and filename
[1926]165        # We put them at x=0.25*pagewidth so that the line is long enough to hold them
[1923]166        title = self.getVar("PYKOTATITLE")
[1934]167        ypos -= self.printVar(c, xcenter / 2.0, ypos, _("Title"), title, 10, savetoner) 
[1923]168       
169        filename = self.getVar("PYKOTAFILENAME")
[1934]170        ypos -= self.printVar(c, xcenter / 2.0, ypos, _("Filename"), filename, 10, savetoner) 
[1923]171       
172        # skip some space
173        ypos -= 20
174       
175        # Now outputs the user's account balance or page counter
[1934]176        ypos -= self.printVar(c, xcenter, ypos, _("Pages printed so far on %s") % printername, self.getVar("PYKOTAPAGECOUNTER"), 14, savetoner) 
[1923]177        limitby = self.getVar("PYKOTALIMITBY")
178        if limitby == "balance" : 
[1934]179            ypos -= self.printVar(c, xcenter, ypos, _("Account balance"), self.getVar("PYKOTABALANCE"), 14, savetoner) 
[2627]180        elif limitby == "quota" :
[1934]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) 
[2627]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)
[1923]194           
195        # URL
196        if url :
[1911]197            c.saveState()
[1923]198            c.setFont("Courier-Bold", 16)
[1934]199            (r, g, b) =  [ color + (savetoner * (1.0 - color)) for color in (0, 0, 1) ] # Blue * savetoner
[1923]200            c.setFillColorRGB(r, g, b)
201            c.drawCentredString(xcenter, 2 * cm, url)
[1911]202            c.restoreState()
203       
204        c.showPage()
205        c.save()
206        return document.getvalue()
[1923]207       
[2193]208    def main(self, arguments, options) :
[1911]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           
[1918]215        self.logdebug("Generating the banner in PDF format...")   
[3319]216        doc = self.genPDF(getPageSize(options.pagesize),
[3305]217                          options.logo.strip().encode(sys.getfilesystemencoding(), "replace"), 
218                          options.url.strip(), 
[2193]219                          " ".join(arguments).strip(), 
[3319]220                          options.savetoner)
[1918]221       
222        self.logdebug("Converting the banner to PostScript...")   
[3319]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()
[1918]234        if os.WIFEXITED(status) :
235            status = os.WEXITSTATUS(status)
236        self.logdebug("PDF to PostScript converter exit code is %s" % str(status))
[3319]237        sys.stdout.write(out)
238        sys.stdout.flush()
[1918]239        self.logdebug("Banner completed.")
240        return status
[1911]241
[1908]242if __name__ == "__main__" :
[3330]243    def checkandset_pagesize(option, opt, value, optionparser) :
[3319]244        """Checks and sets the page size."""
245        if getPageSize(value) is None :
246            loginvalidparam(opt, value, option.default)
[3330]247            setattr(optionparser.values, option.dest, option.default)
[3319]248        else :   
[3330]249            setattr(optionparser.values, option.dest, value)
[3319]250       
[3330]251    def checkandset_savetoner(option, opt, value, optionparser) :   
[3319]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)"))
[3331]256            setattr(optionparser.values, option.dest, option.default / 100.0)
[3319]257        else :   
[3330]258            setattr(optionparser.values, option.dest, value / 100.0)
[3319]259       
[1909]260    # TODO : --papertray : to print banners on a different paper (colored for example)
[3326]261    parser = PyKotaOptionParser(description=_("Banner generator for PyKota."))
[3305]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",
[3319]267                            type="string",
268                            action="callback",
269                            callback=checkandset_pagesize,
[3305]270                            dest="pagesize",
271                            default=u"A4",
[3325]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"))
[3305]273    parser.add_option("-s", "--savetoner",
[3319]274                            type="float",
275                            action="callback",
276                            callback=checkandset_savetoner,
[3305]277                            dest="savetoner",
[3319]278                            default=0.0,
[3325]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."))
[3305]280    parser.add_option("-u", "--url",
281                            dest="url",
282                            default=u"http://www.pykota.com",
[3325]283                            help=_("Set the url to write at the bottom of the banner page. The default url is %default"))
[3305]284    parser.add_example('--logo="" --savetoner=75',
[3319]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.