root / pykota / trunk / bin / pkbanner @ 1925

Revision 1925, 13.8 kB (checked in by jalet, 19 years ago)

Now outputs strings as-is, and not title-ized

  • 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: ISO-8859-15 -*-
3
4# A banner generator for PyKota
5#
6# PyKota - Print Quotas for CUPS and LPRng
7#
8# (c) 2003-2004 Jerome Alet <alet@librelogiciel.com>
9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation; either version 2 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program; if not, write to the Free Software
21# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
22#
23# $Id$
24#
25# $Log$
26# Revision 1.6  2004/11/15 22:20:27  jalet
27# Now outputs strings as-is, and not title-ized
28#
29# Revision 1.5  2004/11/15 22:01:34  jalet
30# Improved banner handling.
31# Fix for raw printing and banners.
32#
33# Revision 1.4  2004/11/15 19:59:34  jalet
34# PyKota banners now basically work !
35#
36# Revision 1.3  2004/11/12 23:46:44  jalet
37# Heavy work on pkbanner. Not finished yet though, but mostly works.
38#
39# Revision 1.2  2004/11/11 14:25:48  jalet
40# Added some TODO comments
41#
42# Revision 1.1  2004/11/10 22:48:47  jalet
43# Banner generator's skeleton added
44#
45#
46#
47
48import sys
49import os
50import time
51import cStringIO
52import popen2
53
54try :
55    from reportlab.pdfgen import canvas
56    from reportlab.lib import pagesizes
57    from reportlab.lib.units import cm
58except ImportError :   
59    hasRL = 0
60else :   
61    hasRL = 1
62   
63try :
64    import PIL.Image 
65except ImportError :   
66    hasPIL = 0
67else :   
68    hasPIL = 1
69   
70from pykota.tool import Tool, PyKotaToolError, crashed, N_
71
72__doc__ = N_("""pkbanner v%s (c) 2003-2004 C@LL - Conseil Internet & Logiciels Libres
73
74Generates banners.
75
76command line usage :
77
78  pkbanner  [options]  [files]
79
80options :
81
82  -v | --version       Prints pkbanner's version number then exits.
83  -h | --help          Prints this message then exits.
84 
85  -d | --darkness d    Sets the darkness to d%%. This can be used to
86                       save toner. The default value is 100.
87                       NOT IMPLEMENTED YET.
88 
89  -p | --pagesize sz   Sets sz as the page size. Most well known
90                       page sizes are recognized, like 'A4' or 'Letter'
91                       to name a few.
92 
93  -l | --logo img      Use the image as the banner's logo. The logo will
94                       be drawn at the top center of the page. The default
95                       logo is /usr/share/pykota/logos/pykota.jpeg
96                       
97  -u | --url u         Uses u as an url to be written at the bottom of
98                       the banner page. The default url is :
99                       http://www.librelogiciel.com/software/
100 
101examples :                             
102
103  Using pkbanner directly from the command line is not recommended,
104  excepted for testing purposes. You should use pkbanner in the
105  'startingbanner' or 'endingbanner' directives in pykota.conf
106 
107  For this reason, there's no example.
108
109This program is free software; you can redistribute it and/or modify
110it under the terms of the GNU General Public License as published by
111the Free Software Foundation; either version 2 of the License, or
112(at your option) any later version.
113
114This program is distributed in the hope that it will be useful,
115but WITHOUT ANY WARRANTY; without even the implied warranty of
116MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
117GNU General Public License for more details.
118
119You should have received a copy of the GNU General Public License
120along with this program; if not, write to the Free Software
121Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
122
123Please e-mail bugs to: %s""")
124       
125class PyKotaBanner(Tool) :       
126    """A class for pkbanner."""
127    primaryfields = [ 
128                ("PRINTERNAME", N_("Printer")),
129                ("JOBID", N_("JobId")),
130                ("JOBORIGINATINGHOSTNAME", N_("Client host")),
131                ("TITLE", N_("Title")),
132                ("FILENAME", N_("Filename")),
133                ("COPIES", N_("Copies")),
134                ("JOBSIZEBYTES", N_("Job size in bytes")),
135                ("PRECOMPUTEDJOBSIZE", N_("Estimated job size")),
136                ("PRECOMPUTEDJOBPRICE", N_("Estimated job price")),
137             ]   
138             
139    secondaryfields = [
140                ("LIMITBY", N_("Account limited by")),
141                ("BALANCE", N_("Account balance")),
142                ("PAGECOUNTER", N_("Number of pages on this printer")),
143                ("SOFTLIMIT", N_("Soft limit")),
144                ("HARDLIMIT", N_("Hard limit")),
145                ("DATELIMIT", N_("Date limit")),
146             ]                           
147   
148    tertiaryfields = [
149                ("ACTION", N_("Action taken for current job")),
150             ]                           
151   
152    def getPageSize(self, pgsize) :
153        """Returns the correct page size or None if not found."""
154        try :
155            return getattr(pagesizes, pgsize.upper())
156        except AttributeError :   
157            try :
158                return getattr(pagesizes, pgsize.lower())
159            except AttributeError :
160                pass
161               
162    def getVar(self, varname) :           
163        """Extracts a variable from the environment and returns its value or 'Unknown' in the current locale."""
164        return os.environ.get(varname) or _("Unknown")
165       
166    def printVar(self, canvas, x, y, label, value, size, darkness) :
167        """Outputs a variable onto the PDF canvas.
168       
169           Returns the number of points to substract to current Y coordinate.
170        """   
171        canvas.saveState()
172        canvas.setFont("Helvetica-Bold", size)
173        (r, g, b) =  (0, 0, 0)  # Black : TODO : darkness
174        canvas.setFillColorRGB(r, g, b)
175        message = "%s :" % _(label)
176        canvas.drawRightString(x, y, message)
177        canvas.setFont("Courier-Bold", size)
178        (r, g, b) = (1, 0, 0)   # Red : TODO : darkness
179        canvas.setFillColorRGB(r, g, b)
180        canvas.drawString(x + 0.5*cm, y, value)
181        canvas.restoreState()
182        return (size + 4)
183   
184    def genPDF(self, pagesize, logo, url, darkness) :
185        """Generates the banner in PDF format, return the PDF document as a string."""
186       
187        document = cStringIO.StringIO()
188        c = canvas.Canvas(document, pagesize=pagesize, pageCompression=1)
189       
190        c.setAuthor("Jerome Alet")
191        c.setTitle("PyKota generated Banner")
192        c.setSubject("This is a print banner generated with PyKota")
193       
194        xcenter = pagesize[0] / 2.0
195        ycenter = pagesize[1] / 2.0
196                   
197        ypos = pagesize[1] - (2 * cm)           
198       
199        if logo :
200            try :   
201                imglogo = PIL.Image.open(logo)
202            except :   
203                self.printInfo("Unable to open image %s" % logo, "warn")
204            else :
205                (width, height) = imglogo.size
206                multi = float(width) / (8 * cm) 
207                width = float(width) / multi
208                height = float(height) / multi
209                xpos = xcenter - (width / 2.0)
210                ypos -= height
211                c.drawImage(logo, xpos, ypos, width, height)
212       
213        # New top
214        xpos = pagesize[0] / 5.0
215        ypos -= (1 * cm) + 20
216       
217        printername = self.getVar("PYKOTAPRINTERNAME")
218        username = self.getVar("PYKOTAUSERNAME")
219        accountbanner = self.config.getAccountBanner(printername)
220       
221        # Outputs the username
222        ypos -= self.printVar(c, xcenter, ypos, _("Username"), username, 20, darkness) 
223       
224        # Printer and Job Id
225        job = "%s - %s" % (printername, self.getVar("PYKOTAJOBID"))
226        ypos -= self.printVar(c, xcenter, ypos, _("Job"), job, 14, darkness) 
227       
228        # Current date (TODO : at the time the banner was printed ! Change this to job's submission date)
229        datetime = time.strftime("%c", time.localtime())
230        ypos -= self.printVar(c, xcenter, ypos, _("Date"), datetime, 14, darkness) 
231       
232        # Result of the print job
233        action = self.getVar("PYKOTAACTION")
234        if action == "ALLOW" :
235            action = _("Allowed")
236        elif action == "DENY" :   
237            action = _("Denied")
238        elif action == "WARN" :   
239            action = _("Allowed with Warning")
240        ypos -= self.printVar(c, xcenter, ypos, _("Result"), action, 14, darkness) 
241       
242        # skip some space
243        ypos -= 20
244       
245        # Outputs title and filename
246        title = self.getVar("PYKOTATITLE")
247        ypos -= self.printVar(c, xcenter, ypos, _("Title"), title, 10, darkness) 
248       
249        filename = self.getVar("PYKOTAFILENAME")
250        ypos -= self.printVar(c, xcenter, ypos, _("Filename"), filename, 10, darkness) 
251       
252        # skip some space
253        ypos -= 20
254       
255        # Now outputs the user's account balance or page counter
256        ypos -= self.printVar(c, xcenter, ypos, _("Pages printed so far on %s") % printername, self.getVar("PYKOTAPAGECOUNTER"), 14, darkness) 
257        limitby = self.getVar("PYKOTALIMITBY")
258        if limitby == "balance" : 
259            ypos -= self.printVar(c, xcenter, ypos, _("Account balance"), self.getVar("PYKOTABALANCE"), 14, darkness) 
260        else :
261            ypos -= self.printVar(c, xcenter, ypos, _("Soft Limit"), self.getVar("PYKOTASOFTLIMIT"), 14, darkness) 
262            ypos -= self.printVar(c, xcenter, ypos, _("Hard Limit"), self.getVar("PYKOTAHARDLIMIT"), 14, darkness) 
263            ypos -= self.printVar(c, xcenter, ypos, _("Date Limit"), self.getVar("PYKOTADATELIMIT"), 14, darkness) 
264           
265        # URL
266        if url :
267            c.saveState()
268            c.setFont("Courier-Bold", 16)
269            (r, g, b) = (0, 0, 1)   # Blue : TODO : darkness
270            c.setFillColorRGB(r, g, b)
271            c.drawCentredString(xcenter, 2 * cm, url)
272            c.restoreState()
273       
274        c.showPage()
275        c.save()
276        return document.getvalue()
277       
278    def main(self, files, options) :
279        """Generates a banner."""
280        if not hasRL :
281            raise PyKotaToolError, "The ReportLab module is missing. Download it from http://www.reportlab.org"
282        if not hasPIL :
283            raise PyKotaToolError, "The Python Imaging Library is missing. Download it from http://www.pythonware.com/downloads"
284           
285        try :
286            darkness = int(options["darkness"])
287            if (darkness <= 0) or (darkness > 100) :
288                raise ValueError, "Allowed range is (1..100)"
289            darkness /= 100.0   
290        except (TypeError, ValueError), msg :
291            self.printInfo("Invalid darkness value %s : %s" % (options["darkness"], msg), "warn")
292            darkness = 1.0
293           
294        pagesize = self.getPageSize(options["pagesize"])
295        if pagesize is None :
296            pagesize = self.getPageSize("a4")
297            self.printInfo("Unknown page size %s, defaulting to A4." % options["pagesize"], "warn")
298           
299        self.logdebug("Generating the banner in PDF format...")   
300        doc = self.genPDF(pagesize, options["logo"].strip(), options["url"].strip(), darkness)
301       
302        self.logdebug("Converting the banner to PostScript...")   
303        os.environ["PATH"] = "%s:/bin:/usr/bin:/usr/local/bin:/opt/bin:/sbin:/usr/sbin" % os.environ.get("PATH", "")
304        child = popen2.Popen3("gs -q -dNOPAUSE -dBATCH -dPARANOIDSAFER -sDEVICE=pswrite -sOutputFile=- - 2>/tmp/errgs")
305        child.tochild.write(doc)
306        child.tochild.close()
307        sys.stdout.write(child.fromchild.read())
308        sys.stdout.flush()
309        child.fromchild.close()
310        status = child.wait()
311        if os.WIFEXITED(status) :
312            status = os.WEXITSTATUS(status)
313        self.logdebug("PDF to PostScript converter exit code is %s" % str(status))
314        self.logdebug("Banner completed.")
315        return status
316
317def getInfo(name) :
318    """Extracts some information from the environment."""
319    return os.environ.get(name, _("Unknown"))
320
321if __name__ == "__main__" :
322    # TODO : --papertray : to print banners on a different paper (colored for example)
323    retcode = 0
324    try :
325        defaults = { \
326                     "darkness" : "100", \
327                     "pagesize" : "a4", \
328                     "logo" : "/usr/share/pykota/logos/pykota.jpeg",
329                     "url" : "http://www.librelogiciel.com/software/",
330                   }
331        short_options = "vhd:l:p:u:"
332        long_options = ["help", "version", "darkness=", "pagesize=", "logo=", "url="]
333       
334        # Initializes the command line tool
335        banner = PyKotaBanner(doc=__doc__)
336       
337        # parse and checks the command line
338        (options, args) = banner.parseCommandline(sys.argv[1:], short_options, long_options, allownothing=1)
339       
340        # sets long options
341        options["help"] = options["h"] or options["help"]
342        options["version"] = options["v"] or options["version"]
343        options["darkness"] = options["d"] or options["darkness"] or defaults["darkness"]
344        options["pagesize"] = options["p"] or options["pagesize"] or defaults["pagesize"]
345        options["logo"] = options["l"] or options["logo"] or defaults["logo"]
346        options["url"] = options["u"] or options["url"] or defaults["url"]
347       
348        if options["help"] :
349            banner.display_usage_and_quit()
350        elif options["version"] :
351            banner.display_version_and_quit()
352        else :
353            retcode = banner.main(args, options)
354    except SystemExit :       
355        pass
356    except :
357        try :
358            banner.crashed("pkbanner failed")
359        except :   
360            crashed("pkbanner failed")
361        retcode = -1
362       
363    sys.exit(retcode)   
Note: See TracBrowser for help on using the browser.