#! /usr/bin/env python # -*- coding: ISO-8859-15 -*- # A banner generator for PyKota # # PyKota - Print Quotas for CUPS and LPRng # # (c) 2003-2004 Jerome Alet # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. # # $Id$ # # $Log$ # Revision 1.8 2004/11/17 13:12:04 jalet # Implemented the --savetoner command line option # # Revision 1.7 2004/11/15 22:29:01 jalet # Moved title and filename to the left to free some space. # # Revision 1.6 2004/11/15 22:20:27 jalet # Now outputs strings as-is, and not title-ized # # Revision 1.5 2004/11/15 22:01:34 jalet # Improved banner handling. # Fix for raw printing and banners. # # Revision 1.4 2004/11/15 19:59:34 jalet # PyKota banners now basically work ! # # Revision 1.3 2004/11/12 23:46:44 jalet # Heavy work on pkbanner. Not finished yet though, but mostly works. # # Revision 1.2 2004/11/11 14:25:48 jalet # Added some TODO comments # # Revision 1.1 2004/11/10 22:48:47 jalet # Banner generator's skeleton added # # # import sys import os import time import cStringIO import popen2 try : from reportlab.pdfgen import canvas from reportlab.lib import pagesizes from reportlab.lib.units import cm except ImportError : hasRL = 0 else : hasRL = 1 try : import PIL.Image except ImportError : hasPIL = 0 else : hasPIL = 1 from pykota.tool import Tool, PyKotaToolError, crashed, N_ __doc__ = N_("""pkbanner v%s (c) 2003-2004 C@LL - Conseil Internet & Logiciels Libres Generates banners. command line usage : pkbanner [options] [files] options : -v | --version Prints pkbanner's version number then exits. -h | --help Prints this message then exits. -l | --logo img Use the image as the banner's logo. The logo will be drawn at the top center of the page. The default logo is /usr/share/pykota/logos/pykota.jpeg -p | --pagesize sz Sets sz as the page size. Most well known page sizes are recognized, like 'A4' or 'Letter' to name a few. The default size is A4. -s | --savetoner s Sets the text luminosity factor to d%%. This can be used to save toner. The default value is 0, which means that no toner saving will be done. -u | --url u Uses u as an url to be written at the bottom of the banner page. The default url is : http://www.librelogiciel.com/software/ examples : Using pkbanner directly from the command line is not recommended, excepted for testing purposes. You should use pkbanner in the 'startingbanner' or 'endingbanner' directives in pykota.conf For this reason, there's no example. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. Please e-mail bugs to: %s""") class PyKotaBanner(Tool) : """A class for pkbanner.""" def getPageSize(self, pgsize) : """Returns the correct page size or None if not found.""" try : return getattr(pagesizes, pgsize.upper()) except AttributeError : try : return getattr(pagesizes, pgsize.lower()) except AttributeError : pass def getVar(self, varname) : """Extracts a variable from the environment and returns its value or 'Unknown' in the current locale.""" return os.environ.get(varname) or _("Unknown") def printVar(self, canvas, x, y, label, value, size, savetoner) : """Outputs a variable onto the PDF canvas. Returns the number of points to substract to current Y coordinate. """ canvas.saveState() canvas.setFont("Helvetica-Bold", size) (r, g, b) = [ color + (savetoner * (1.0 - color)) for color in (0, 0, 0) ] # Black * savetoner canvas.setFillColorRGB(r, g, b) message = "%s :" % _(label) canvas.drawRightString(x, y, message) canvas.setFont("Courier-Bold", size) (r, g, b) = [ color + (savetoner * (1.0 - color)) for color in (1, 0, 0) ] # Red * savetoner canvas.setFillColorRGB(r, g, b) canvas.drawString(x + 0.5*cm, y, value) canvas.restoreState() return (size + 4) def genPDF(self, pagesize, logo, url, savetoner) : """Generates the banner in PDF format, return the PDF document as a string.""" document = cStringIO.StringIO() c = canvas.Canvas(document, pagesize=pagesize, pageCompression=1) c.setAuthor("Jerome Alet") c.setTitle("PyKota generated Banner") c.setSubject("This is a print banner generated with PyKota") xcenter = pagesize[0] / 2.0 ycenter = pagesize[1] / 2.0 ypos = pagesize[1] - (2 * cm) if logo : try : imglogo = PIL.Image.open(logo) except : self.printInfo("Unable to open image %s" % logo, "warn") else : (width, height) = imglogo.size multi = float(width) / (8 * cm) width = float(width) / multi height = float(height) / multi xpos = xcenter - (width / 2.0) ypos -= height c.drawImage(logo, xpos, ypos, width, height) # New top xpos = pagesize[0] / 5.0 ypos -= (1 * cm) + 20 printername = self.getVar("PYKOTAPRINTERNAME") username = self.getVar("PYKOTAUSERNAME") accountbanner = self.config.getAccountBanner(printername) # Outputs the username ypos -= self.printVar(c, xcenter, ypos, _("Username"), username, 20, savetoner) # Printer and Job Id job = "%s - %s" % (printername, self.getVar("PYKOTAJOBID")) ypos -= self.printVar(c, xcenter, ypos, _("Job"), job, 14, savetoner) # Current date (TODO : at the time the banner was printed ! Change this to job's submission date) datetime = time.strftime("%c", time.localtime()) ypos -= self.printVar(c, xcenter, ypos, _("Date"), datetime, 14, savetoner) # Result of the print job action = self.getVar("PYKOTAACTION") if action == "ALLOW" : action = _("Allowed") elif action == "DENY" : action = _("Denied") elif action == "WARN" : action = _("Allowed with Warning") ypos -= self.printVar(c, xcenter, ypos, _("Result"), action, 14, savetoner) # skip some space ypos -= 20 # Outputs title and filename # We put them at x=0.25*pagewidth so that the line is long enough to hold them title = self.getVar("PYKOTATITLE") ypos -= self.printVar(c, xcenter / 2.0, ypos, _("Title"), title, 10, savetoner) filename = self.getVar("PYKOTAFILENAME") ypos -= self.printVar(c, xcenter / 2.0, ypos, _("Filename"), filename, 10, savetoner) # skip some space ypos -= 20 # Now outputs the user's account balance or page counter ypos -= self.printVar(c, xcenter, ypos, _("Pages printed so far on %s") % printername, self.getVar("PYKOTAPAGECOUNTER"), 14, savetoner) limitby = self.getVar("PYKOTALIMITBY") if limitby == "balance" : ypos -= self.printVar(c, xcenter, ypos, _("Account balance"), self.getVar("PYKOTABALANCE"), 14, savetoner) else : ypos -= self.printVar(c, xcenter, ypos, _("Soft Limit"), self.getVar("PYKOTASOFTLIMIT"), 14, savetoner) ypos -= self.printVar(c, xcenter, ypos, _("Hard Limit"), self.getVar("PYKOTAHARDLIMIT"), 14, savetoner) ypos -= self.printVar(c, xcenter, ypos, _("Date Limit"), self.getVar("PYKOTADATELIMIT"), 14, savetoner) # URL if url : c.saveState() c.setFont("Courier-Bold", 16) (r, g, b) = [ color + (savetoner * (1.0 - color)) for color in (0, 0, 1) ] # Blue * savetoner c.setFillColorRGB(r, g, b) c.drawCentredString(xcenter, 2 * cm, url) c.restoreState() c.showPage() c.save() return document.getvalue() def main(self, files, options) : """Generates a banner.""" if not hasRL : raise PyKotaToolError, "The ReportLab module is missing. Download it from http://www.reportlab.org" if not hasPIL : raise PyKotaToolError, "The Python Imaging Library is missing. Download it from http://www.pythonware.com/downloads" try : savetoner = int(options["savetoner"]) if (savetoner < 0) or (savetoner > 99) : raise ValueError, _("Allowed range is (0..99)") savetoner /= 100.0 except (TypeError, ValueError), msg : self.printInfo(_("Invalid 'savetoner' option %s : %s") % (options["savetoner"], msg), "warn") savetoner = 0.0 pagesize = self.getPageSize(options["pagesize"]) if pagesize is None : pagesize = self.getPageSize("a4") self.printInfo(_("Invalid 'pagesize' option %s, defaulting to A4.") % options["pagesize"], "warn") self.logdebug("Generating the banner in PDF format...") doc = self.genPDF(pagesize, options["logo"].strip(), options["url"].strip(), savetoner) self.logdebug("Converting the banner to PostScript...") os.environ["PATH"] = "%s:/bin:/usr/bin:/usr/local/bin:/opt/bin:/sbin:/usr/sbin" % os.environ.get("PATH", "") child = popen2.Popen3("gs -q -dNOPAUSE -dBATCH -dPARANOIDSAFER -sDEVICE=pswrite -sOutputFile=- - 2>/tmp/errgs") child.tochild.write(doc) child.tochild.close() sys.stdout.write(child.fromchild.read()) sys.stdout.flush() child.fromchild.close() status = child.wait() if os.WIFEXITED(status) : status = os.WEXITSTATUS(status) self.logdebug("PDF to PostScript converter exit code is %s" % str(status)) self.logdebug("Banner completed.") return status if __name__ == "__main__" : # TODO : --papertray : to print banners on a different paper (colored for example) retcode = 0 try : defaults = { \ "savetoner" : "100", \ "pagesize" : "a4", \ "logo" : "/usr/share/pykota/logos/pykota.jpeg", "url" : "http://www.librelogiciel.com/software/", } short_options = "vhs:l:p:u:" long_options = ["help", "version", "savetoner=", "pagesize=", "logo=", "url="] # Initializes the command line tool banner = PyKotaBanner(doc=__doc__) # parse and checks the command line (options, args) = banner.parseCommandline(sys.argv[1:], short_options, long_options, allownothing=1) # sets long options options["help"] = options["h"] or options["help"] options["version"] = options["v"] or options["version"] options["savetoner"] = options["s"] or options["savetoner"] or defaults["savetoner"] options["pagesize"] = options["p"] or options["pagesize"] or defaults["pagesize"] options["url"] = options["u"] or options["url"] or defaults["url"] options["logo"] = options["l"] or options["logo"] if options["logo"] is None : # Allows --logo="" to disable the logo entirely options["logo"] = defaults["logo"] if options["help"] : banner.display_usage_and_quit() elif options["version"] : banner.display_version_and_quit() else : retcode = banner.main(args, options) except SystemExit : pass except : try : banner.crashed("pkbanner failed") except : crashed("pkbanner failed") retcode = -1 sys.exit(retcode)